QT中使用一个信号量来写日志文件?

QT中使用一个信号量来写日志文件?,第1张

你的代码我是懒得看了;看了前面一点,就觉得你这写的有问题,没有充分利用QT带的功能。给你个我的思路:

(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


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/436240.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-28
下一篇2023-05-28

发表评论

登录后才能评论

评论列表(0条)

    保存