Chinaunix首页 | 论坛 | 博客
  • 博客访问: 42470
  • 博文数量: 30
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2020-10-13 16:47
文章分类

全部博文(30)

文章存档

2020年(30)

我的朋友

分类: LINUX

2020-10-13 16:50:03

   原创文章,转载请注明出处,谢谢!       
       作者:清林,博客名:飞空静渡
 

       QVariant可以表示QT中的大部分类型,它和pascal中的variant类型或c中的void类型有点相似,不过它的使用和c中的union类似,其实现也是用union,在qvariant.h头文件中,我们可以看到这样定义:
       view plaincopy to clipboardprint?
class Q_CORE_EXPORT QVariant  
{  
  public:  
     enum Type {  
         Invalid = 0,  
   
         Bool = 1,  
         Int = 2,  
         UInt = 3,  
         LongLong = 4,  
         ULongLong = 5,  
......  
        UserType = 127,  
 #ifdef QT3_SUPPORT  
         IconSet = Icon,  
         CString = ByteArray,  
         PointArray = Polygon,  
 #endif  
         LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type  
     };  
   
     inline QVariant();  
...............  

class Q_CORE_EXPORT QVariant
{
  public:
     enum Type {
         Invalid = 0,
 
         Bool = 1,
         Int = 2,
         UInt = 3,
         LongLong = 4,
         ULongLong = 5,
......
        UserType = 127,
 #ifdef QT3_SUPPORT
         IconSet = Icon,
         CString = ByteArray,
         PointArray = Polygon,
 #endif
         LastType = 0xffffffff // need this so that gcc >= 3.4 allocates 32 bits for Type
     };
 
     inline QVariant();
...............
}

      
我们可以用type()成员函数来返回它的类型:Type   QVariant::type () const 。
为了取得它的值,我们可以用类似的toT()这样的函数来取得,如toInt()、toString()等。
基本的使用如下:
view plaincopy to clipboardprint?
QDataStream out(...);  
 QVariant v(123);                // The variant now contains an int  
 int x = v.toInt();              // x = 123  
 out << v;                       // Writes a type tag and an int to out  
 v = QVariant("hello");          // The variant now contains a QByteArray  
 v = QVariant(tr("hello"));      // The variant now contains a QString  
 int y = v.toInt();              // y = 0 since v cannot be converted to an int  
 QString s = v.toString();       // s = tr("hello")  (see QObject::tr())  
 out << v;                       // Writes a type tag and a QString to out  
 ...  
 QDataStream in(...);            // (opening the previously written stream)  
 in >> v;                        // Reads an Int variant  
 int z = v.toInt();              // z = 123  
 qDebug("Type is %s",            // prints "Type is int"  
         v.typeName());  
 v = v.toInt() + 100;            // The variant now hold the value 223  
 v = QVariant(QStringList()); 
QDataStream out(...);
 QVariant v(123);                // The variant now contains an int
 int x = v.toInt();              // x = 123
 out << v;                       // Writes a type tag and an int to out
 v = QVariant("hello");          // The variant now contains a QByteArray
 v = QVariant(tr("hello"));      // The variant now contains a QString
 int y = v.toInt();              // y = 0 since v cannot be converted to an int
 QString s = v.toString();       // s = tr("hello")  (see QObject::tr())
 out << v;                       // Writes a type tag and a QString to out
 ...
 QDataStream in(...);            // (opening the previously written stream)
 in >> v;                        // Reads an Int variant
 int z = v.toInt();              // z = 123
 qDebug("Type is %s",            // prints "Type is int"
         v.typeName());
 v = v.toInt() + 100;            // The variant now hold the value 223
 v = QVariant(QStringList());
 
 
QViriant支持空值的使用,你可以定义一个空的QViriant,并在后面才给它赋值。
view plaincopy to clipboardprint?
QVariant x, y(QString()), z(QString(""));  
x.convert(QVariant::Int);  
// x.isNull() == true  
// y.isNull() == true, z.isNull() == false  
// y.isEmpty() == true, z.isEmpty() == true 
 QVariant x, y(QString()), z(QString(""));
 x.convert(QVariant::Int);
 // x.isNull() == true
 // y.isNull() == true, z.isNull() == false
 // y.isEmpty() == true, z.isEmpty() == true
 

QVariant是定义在QtCore库中的,前面说的qvariant.h就在QtCore目录下,因此它不提供类似于toInt()、toString()这样的函数去转化QtGui中的类型,如QColor、QImage和QPixmap等。但你可以使用 QVariant::value()或者 qVariantValue ()模板函数转化。
view plaincopy to clipboardprint?
QVariant variant;  
...  
QColor color = variant.value(); 
 QVariant variant;
 ...
 QColor color = variant.value();
相反的赋值就可以这样:
view plaincopy to clipboardprint?
QColor color = palette().background().color();  
QVariant variant = color; 
 QColor color = palette().background().color();
 QVariant variant = color;
 

你可以使用 canConvert() 确定是否可以转化。
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fjb2080/archive/2009/12/09/4972915.aspx
 
我们在使用QT编程时,难免要定义自己需要的类型,但像QT自己的类型如QSzie、QString之类的,都是可以存储在QViriant中的,并且这些QT的类型是可以用在基于QObject类的类型属性中和基于信号和槽的发生机制中。
如果我们想要我们自己自定义的类型可以有QT自己类型的功能的话,我们就必须注册我们的类型到QT中,这样我们才可以在我们在信号和槽的通讯机制中使用我们的类型。
在我们想要把我们的类型注册到QT中,我们必须满足QMedaType类型的要求,这有三点是必须的要求(以后章节说的也要满足这三点要求)。

1、必须要有一个公有的构造函数。
2、必须要有一个公有的拷贝构造函数。
3、必须要有一个公有的虚构函数。
 

下面使用QT文档中的一个例子来说明:
第一步:我们首先可以定义一个满足上面三点要求的自定义的类。
view plaincopy to clipboardprint?
#ifndef MESSAGE_H  
#define MESSAGE_H  
#include   
#include   
#include   
class Message  
{  
public:  
    Message();  
    Message(const Message &other);  
    ~Message();  
    Message(const QString &body, const QStringList &headers);  
    QString body() const;  
    QStringList headers() const;  
private:  
    QString m_body;  
    QStringList m_headers;  
};  
Q_DECLARE_METATYPE(Message);  
QDebug &operator<<(QDebug &dbg, const Message &message);  
#endif 
 #ifndef MESSAGE_H
 #define MESSAGE_H
 #include
 #include
 #include
 class Message
 {
 public:
     Message();
     Message(const Message &other);
     ~Message();
     Message(const QString &body, const QStringList &headers);
     QString body() const;
     QStringList headers() const;
 private:
     QString m_body;
     QStringList m_headers;
 };
 Q_DECLARE_METATYPE(Message);
 QDebug &operator<<(QDebug &dbg, const Message &message);
 #endif
 
 
第二步:注册我们的类型
我们的自定义的类型,在QT中的QVariant中的,因为在QVariant中并不知道怎么存储和获取我们的类型。因此我们就必须使我们的类型成为和QString一样的通用类型,这就需要QT中的QMetaType来完成了。我们需要调用 Q_DECLARE_METATYPE这个宏来完成。

 Q_DECLARE_METATYPE(Message);
这就可以使我们的Message可以存储在QVariant中了。Q_DECLARE_METATYPE可以使我们的类型使用在信号的参数中,但是直接使用在信号-槽的通讯中的,但不可以用在基于消息队列中的信号-槽的机制中的,例如我们在线程中的通讯,上面的那种定义就做不到了。这是因为,上面的那种定义是用宏来静态定义的,在QT中的元对象系统中并不知道在运行时怎么创建和销毁我们的自定义的对象。我将在后一章讲解我们自定义的类型完全用在信号-槽的通讯机制中的做法。
 

这是Message的实现代码:
view plaincopy to clipboardprint?
#include "message.h"  
 Message::Message()  
 {  
 }  
 Message::Message(const Message &other)  
 {  
     m_body = other.m_body;  
     m_headers = other.m_headers;  
 }  
 Message::~Message()  
 {  
 }  
 Message::Message(const QString &body, const QStringList &headers)  
 {  
     m_body = body;  
     m_headers = headers;  
 }  
 QDebug &operator<<(QDebug &dbg, const Message &message)  
 {  
     QStringList pieces = message.body().split("\r\n", QString::SkipEmptyParts);  
     if (pieces.isEmpty())  
         dbg.nospace() << "Message()";  
     else if (pieces.size() == 1)  
         dbg.nospace() << "Message(" << pieces.first() << ")";  
     else 
         dbg.nospace() << "Message(" << pieces.first() << " ...)";  
     return dbg.maybeSpace();  
 }  
 QString Message::body() const 
 {  
     return m_body;  
 }  
 QStringList Message::headers() const 
 {  
     return m_headers;  
 } 
#include "message.h"
 Message::Message()
 {
 }
 Message::Message(const Message &other)
 {
     m_body = other.m_body;
     m_headers = other.m_headers;
 }
 Message::~Message()
 {
 }
 Message::Message(const QString &body, const QStringList &headers)
 {
     m_body = body;
     m_headers = headers;
 }
 QDebug &operator<<(QDebug &dbg, const Message &message)
 {
     QStringList pieces = message.body().split("\r\n", QString::SkipEmptyParts);
     if (pieces.isEmpty())
         dbg.nospace() << "Message()";
     else if (pieces.size() == 1)
         dbg.nospace() << "Message(" << pieces.first() << ")";
     else
         dbg.nospace() << "Message(" << pieces.first() << " ...)";
     return dbg.maybeSpace();
 }
 QString Message::body() const
 {
     return m_body;
 }
 QStringList Message::headers() const
 {
     return m_headers;
 }
 
 
 

最后看下我们的main函数。
view plaincopy to clipboardprint?
#include   
 #include   
 #include "message.h"  
 int main(int argc, char *argv[])  
 {  
     QCoreApplication app(argc, argv);  
     QStringList headers;  
     headers << "Subject: Hello World" 
             << "From: ";  
     QString body = "This is a test.\r\n";  
     Message message(body, headers);  
     qDebug() << "Original:" << message;  
     QVariant stored;  
     stored.setValue(message);  
     qDebug() << "Stored:" << stored;  
     Message retrieved = stored.value();  
     qDebug() << "Retrieved:" << retrieved;  
     retrieved = qVariantValue(stored);  
     qDebug() << "Retrieved:" << retrieved;  
     return 0;  
 } 
#include
 #include
 #include "message.h"
 int main(int argc, char *argv[])
 {
     QCoreApplication app(argc, argv);
     QStringList headers;
     headers << "Subject: Hello World"
             << "From: ";
     QString body = "This is a test.\r\n";
     Message message(body, headers);
     qDebug() << "Original:" << message;
     QVariant stored;
     stored.setValue(message);
     qDebug() << "Stored:" << stored;
     Message retrieved = stored.value();
     qDebug() << "Retrieved:" << retrieved;
     retrieved = qVariantValue(stored);
     qDebug() << "Retrieved:" << retrieved;
     return 0;
 }
 
 
我们在注册我们的Message类后,我们就可以使我们的Message类对象存储在我们的QVariant的对象中了。在main函数中,我们可以看到

     QVariant stored;
     stored.setValue(message);
而从QVariant中获得我们的对象可以这样:

Message retrieved = stored.value();
pro文件:

 HEADERS   = message.h
 SOURCES   = main.cpp \
             message.cpp
下一章讲解用这个例子用在信号-槽的通讯机制中,后一章将讲解自定义类型在消息队列的信号-槽的机制,即在多线程通讯中使自定义类型在信号-槽中的运用。
 
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fjb2080/archive/2009/12/10/4977342.aspx
 
   昨天调试项目时,突然发现如下消息:

QObject::connect: Cannot queue arguments of type 'ERROR_LEVEL'
(Make sure 'ERROR_LEVEL' is registered using qRegisterMetaType().)

其中ERROR_LEVEL只是我定义的枚举类型即enum ERROR_LEVEL。然后在Qt的信号-槽函数的参数中使用了这个枚举型,在发送信号时就出现了上述警告。上面警告的大概意思是信号队列中无法使用ERROR_LEVEL类型,要使用qRegisterMetaType()注册该类型后方可使用。

      通常使用的connect,实际上最后一个参数使用的是Qt::AutoConnection类型:

bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection )

Qt支持6种连接方式,其中3中最主要:

  • Qt::DirectConnection(直连方式)

      当信号发出后,相应的槽函数将立即被调用。emit语句后的代码将在所有槽函数执行完毕后被执行。(信号与槽函数关系类似于函数调用,同步执行

  • Qt::QueuedConnection(排队方式)

      当信号发出后,排队到信号队列中,需等到接收对象所属线程的事件循环取得控制权时才取得该信号,调用相应的槽函数。emit语句后的代码将在发出信号后立即被执行,无需等待槽函数执行完毕。(此时信号被塞到信号队列里了,信号与槽函数关系类似于消息通信,异步执行

  • Qt::AutoConnection(自动方式)

      Qt的默认连接方式,如果信号的发出和接收这个信号的对象同属一个线程,那个工作方式与直连方式相同;否则工作方式与排队方式相同。

      我的项目中的确跨线程使用了ERROR_LEVEL为参数类型的信号,因此使用的应当是排队方式的信号-槽机制,出现“队列中无法使用ERROR_LEVEL类型”的警告信息就可以理解了。放狗搜了一圈,有篇文章提供了个这样的解决方案:

connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)));
改为:
connect(cm, SIGNAL(sendLog(QUuid, QByteArray, bool)),
            this,SLOT(sendRes(QUuid,QByteArray,bool)), Qt::DirectConnection);

这样做的确能使警告信息消失,因为Qt官方文档写了:

With queued connections, the parameters must be of types that are known to Qt's meta-object system, because Qt needs to copy the arguments to store them in an event behind the scenes.

即使用排队方式的信号-槽机制,Qt的元对象系统(meta-object system)必须知道信号传递的参数类型。这里手动改为直连方式,Qt的元对象系统就不必知道参数类型了,于是警告信息消失。但这样做是不安全的,见Qt官方文档:

Be aware that using direct connections when the sender and receiver live in different threads is unsafe if an event loop is running in the receiver's thread, for the same reason that calling any function on an object living in another thread is unsafe.

      因此,咱还是老老实实地用qRegisterMetaType()注册类型吧,见代码:

头文件

/*! \file errorlevel.h*/
#ifndef ERRORLEVEL_H
#define ERRORLEVEL_H
/*! \enum ERROR_LEVEL
 * 错误等级的定义。通常用来在传递错误消息时标记错误的等级。
 */
enum ERROR_LEVEL
{
    NORMAL,  /*!< 普通错误,通常不需要处理,可以记录或者显示错误消息。*/
    CRITICAL /*!< 严重错误,需要紧急处理,如果没有妥善处理,可能导致后续操作失败。*/
};
#endif // ERRORLEVEL_H

cpp文件

/*! \file errorlevel.cpp*/
#include "errorlevel.h"
/*! 模板函数显式实例化,注册ERROR_LEVEL到元对象系统。这样才可以在信号-槽
 * 队列里使用ERROR_LEVEL类型参数。
 */
int i = qRegisterMetaType("ERROR_LEVEL");
元类型注册方法受益于这篇文章
阅读(1736) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~