(1) 新启动一个QThread thread,该线程只运行一个事件循环(QEventLoop looploop.exec())
(2)将写日志文件功能单独抽象成一个继承QObject的类LogHelp
class LogHelp :public QObject
{
Q_OBJECT
public:
void Write(QString log){emit NotifyWrite(log)}
signal:
void NotifyWrite(QString log)
public slot:
void OnWrite(QString log){/*你的核心写文件代码*/}
(3)LogHelp logHelp 对象需要 movetothread 到(1)中创建的线程;logHelp.moveToThread(&thread)
(4)重点:connect(&logHelp,SIGNAL(NotifyWrite(QString)),&logHelp,SLOT(OnWrite(QString)),Qt::QueuedConnection)
如此你就可以在其它线程中直接调用logHelp .Write(log)不用管数据安全问题。
代码手敲,可能有问题,只是告诉你个思路。这样写不用维护队列,使用的是信号和槽函数的异步队列方式。
使用下面这个struct来做说明(这里不管是struct还是class都一样):
struct Player
{
int number
QString firstName
QString lastName
}
QVariant
为了能在QVariant中使用自定义数据类型做,需要使用Q_DECLARE_METATYPE()来向Qt的元系统声明这个自定义类型。如下列所示:
struct Player
{
...
}
Q_DECLARE_METATYPE(Player)
在作为QVariant传递自定义数据类型时,需要使用QVariant::fromValue()或者qVariantFromValue:
Player player
object->setProperty("property", QVariant::fromValue(player))
为了更方便一点,你可以在自定义类型中定义一个QVariant() 类型转换符:
struct Player
{
...
operator QVariant() const
{
return QVariant::fromValue(*this)
}
}
这样我们便可以像下面这样使用了:
Player player
object->setProperty("property", player)
信号和槽
对于直接连接类型(默认情况下就是直接连接)而言,使用自定义数据类型做信号参数不需要做其他其他处理,就像内置数据类型一样:
connect(sender, SIGNAL(playerCreated(const Player&)), receiver, SLOT(addPlayer(const Player&)))
但在跨线程时如果你还这么做,编译器就会给出警告了:
QObject::connect: Cannot queue arguments of type 'Player'
(Make sure 'Player' is registered using qRegisterMetaType().)
这时我们需要先注册Player:
qRegisterMetaType<Player>("Player")
qRegisterMetaType<Player>( ) (上面那个是错误的,除非名字刚好和类名一样)
connect(sender, SIGNAL(playerCreated(const Player&)), receiver, SLOT(addPlayer(const Player&)))
QDebug
最好是能这样:
qDebug() <<player
而不是这样:
qDebug() <<"Player(" <<player.number <<"," <<player.firstName <<"," <<player.lastName <<")"
怎么做呢?我们需要对QDebug<<操作符重载一下:
inline QDebug operator<<(QDebug debug, const Player&player)
{
debug.nospace() <<"Player("
<<player.number <<","
<<player.firstName <<","
<<player.lastName <<")"
return debug.space()
}
QDataStream
跟上面的QDebug很像,我们也需要重载一下<<操作符:
inline QDataStream&operator<<(QDataStream&out, const Player&player)
{
out <<player.number
out <<player.firstName
out <<player.lastName
return out
}
inline QDataStream&operator>>(QDataStream&in, Player&player)
{
in >>player.number
in >>player.firstName
in >>player.lastName
return in
}
QSettings
QSettings 用QVariant保存键值,用QDataStream序列化自定义数据。(参考后面的variantToString函数)
为了能在QSettings中使用自定义数据类型,需要让Qt的元系统知道有此类型,就像上面介绍QVariant部分一样,另外还要提供相应的QDataStream操作符,还必须注册这个流操作符:
qRegisterMetaTypeStreamOperators<Player>("Player")
如此处理之后我们就可以像下面这样使用了:
QSettings settings
Player player
settings.setValue("key", player)
QSettings settings
Player player = value("key").value<Player>()
参考:
QString QSettingsPrivate::variantToString(const QVariant &v)
{
QString result
switch (v.type()) {
case QVariant::Invalid:
result = QLatin1String("@Invalid()")
break
case QVariant::ByteArray: {
QByteArray a = v.toByteArray()
result = QLatin1String("@ByteArray(")
result += QString::fromLatin1(a.constData(), a.size())
result += QLatin1Char(')')
break
}
case QVariant::String:
case QVariant::LongLong:
case QVariant::ULongLong:
case QVariant::Int:
case QVariant::UInt:
case QVariant::Bool:
case QVariant::Double:
case QVariant::KeySequence: {
result = v.toString()
if (result.startsWith(QLatin1Char('@')))
result.prepend(QLatin1Char('@'))
break
}
#ifndef QT_NO_GEOM_VARIANT
case QVariant::Rect: {
QRect r = qvariant_cast<QRect>(v)
result += QLatin1String("@Rect(")
result += QString::number(r.x())
result += QLatin1Char(' ')
result += QString::number(r.y())
result += QLatin1Char(' ')
result += QString::number(r.width())
result += QLatin1Char(' ')
result += QString::number(r.height())
result += QLatin1Char(')')
break
}
case QVariant::Size: {
QSize s = qvariant_cast<QSize>(v)
result += QLatin1String("@Size(")
result += QString::number(s.width())
result += QLatin1Char(' ')
result += QString::number(s.height())
result += QLatin1Char(')')
break
}
case QVariant::Point: {
QPoint p = qvariant_cast<QPoint>(v)
result += QLatin1String("@Point(")
result += QString::number(p.x())
result += QLatin1Char(' ')
result += QString::number(p.y())
result += QLatin1Char(')')
break
}
#endif // !QT_NO_GEOM_VARIANT
default: {
#ifndef QT_NO_DATASTREAM
QByteArray a
{
QDataStream s(&a, QIODevice::WriteOnly)
s.setVersion(QDataStream::Qt_4_0)
s <<v
}
result = QLatin1String("@Variant(")
result += QString::fromLatin1(a.constData(), a.size())
result += QLatin1Char(')')
#else
Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support")
#endif
break
}
}
return result
}
qsetting为了让保存的ini文件能和ascii兼容,所以
我们将ini文件中的键值读入到 QVariant 中,需要两个步骤:
因为文件内的一些字符被转义了,比如 "\x1234\t\0"等,所以需要 unescape
从 unescape 后的字符串构造出 QVariant
当将QVariant写入文件时:
将 QVariant 转换成字符串
处理字符串中的特殊字符,即 escape
欢迎分享,转载请注明来源:夏雨云
评论列表(0条)