Qt/Qt Quick宏浅议

刚开始接触Qt的朋友可能对Qt在使用当中需要声明的各色各样的宏感到神秘而又陌生,本文将介绍Qt中经常使用的几个宏: Q_OBJECT, SIGNAL与SLOT, Q_SIGNALS 与 Q_SLOTS, Q_EMIT ,Q_INVOKABLE, Q_PROPERTY:

 

宏的头文件出处: $QTDIR/src/corelib/kernel/qobjectdefs.h

Q_OBJECT

#define Q_OBJECT /
public: /
    Q_OBJECT_CHECK /
    static const QMetaObject staticMetaObject; /
    Q_OBJECT_GETSTATICMETAOBJECT /
    virtual const QMetaObject *metaObject() const; /
    virtual void *qt_metacast(const char *); /
    QT_TR_FUNCTIONS /
    virtual int qt_metacall(QMetaObject::Call, int, void **); /

宏Q_OBJECT是Qt所有宏中最为重要的一个,Q_OBJECT是使用信号槽机制以及其他所有元对象系统提供的服务(内省、invokeMethod,元对象property系统等等)的前提条件。有关Q_OBJECT的讨论请参考Qt源码分析之QObject。 

SIGNAL与SLOT

这两个宏是调用connect方法时用到:

  1. QObject::connect(myButton, SIGNAL(clicked()),   
  2.                   label,  SLOT(showText()));  
 

那么宏SIGNAL和SLOT为我们做了那些事情呢,看一下源代码:

  1. $QTDIR/src/corelib/kernel/qobjectdefs.h  
  2. # define SLOT(a)     qFlagLocation("1"#a QLOCATION)    
  3. # define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)   
  4. $QTDIR/src/corelib/kernel/qobject.cpp  
  5. const char *qFlagLocation(const char *method)   
  6. {   
  7.     static int idx = 0;   
  8.     flagged_locations[idx] = method;   
  9.     idx = (idx+1) % flagged_locations_count;   
  10.     return method;   
  11. }  
 

原来它会基于把我们定义的信号、槽的名称返回一个字符串,比如SIGNAL(clicked()) 返回字符串 “2clicked()”, SLOT(showText())返回字符串“1showText()”

  1. Q_SIGNALS 与 Q_SLOTS  
  2. #  define slots    
  3. #  define signals protected    
  4. # define Q_SLOTS    
  5. # define Q_SIGNALS protected  
 

Q_SIGNALS 与 Q_SLOTS是Qt 4.1引入的,它们用来替换关键字signals和slots,原因是更好的与第三方信号槽机制兼容,比如boost库。尽管Q_SIGNALS 与 Q_SLOTS看起来没有做什么。其实不然,QT的元对象编译器moc会识别声明在头文件中的宏Q_SIGNALS,Q_SLOTS。并做为依据,生成元对象模型数据,详见文中最后所示代码实例

Q_EMIT
#define Q_EMIT
#define emit

Q_EMIT用来替换关键字emit,原因也是更好的与第三方信号槽机制兼容,比如boost库。

这里要注意,我们看到Q_EMIT看起来同样的简单, 但它们是有区别的!表面的区别在于Q_SIGNALS 与 Q_SLOTS用在头文件中,而Q_EMIT用在代码视线中。 本质的区别的在于,Q_SIGNALS 与 Q_SLOTS将被moc识别,是必须使用的。而Q_EMIT或者emit是可有可无的。它不会被moc识别,它存在的唯一理由是:增加代码的可读性。  也就是说如下代码都能正常工作,但2)的写法也许会惹怒你的同事。

  1. void method()  
  2. {  
  3.       1) emit signalA();  
  4.       2) signalA();    
  5. }  
 

Q_INVOKABLE

#define Q_INVOKABLE

 

使用Q_INVOKABLE来修饰成员函数,目的在于被修饰的成员函数能够被元对象系统所唤起。这一机制在Qt C++/QML混合编程,Qt service framework, 以及Qt/ HTML5混合编程里广泛使用。我会随后另撰写一文做深入探讨。

 

 

Q_PROPERTY

 

#define Q_PROPERTY(text)   

 

使用Q_PROPERTY用以声明属性,属性类似于成员变量,但它能够被元对象系统所访问。QML的属性便是利用该机制得以实现的。 Q_PROPERTY的用法如下:

 

Q_PROPERTY(QString title READ title WRITE setTitle USER true)

 


 

接下来,让我们结合代码来看一下上述宏的使用以及元对象编译器是如何利用这些宏的。

 

  1. #include <QDeclarativeItem >   
  2. class EllipseItem : public QDeclarativeItem   
  3. {   
  4.     Q_OBJECT   
  5.     Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)  
  6. public:   
  7.     EllipseItem(QDeclarativeItem *parent = 0);   
  8.     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,   
  9.                QWidget *widget = 0);  
  10.     const QColor &color() const;   
  11.     void setColor(const QColor &newColor);  
  12.     Q_INVOKABLE QColor randomColor() const;  
  13. public Q_SLOTS:   
  14.     void try1();   
  15.     void try2() {}  
  16. Q_SIGNALS:   
  17.     void colorChanged();   
  18.     void ready();  
  19. private:   
  20.     QColor m_color;   
  21. };  
 

 

以下代码由元对象编译器moc根据上述头文件自动生成:

 

  1. static const uint qt_meta_data_EllipseItem[] = {  
  2. // content:    
  3.        5,       // revision    
  4.        0,       // classname    
  5.        0,    0, // classinfo    
  6.        5,   14, // methods    
  7.        1,   39, // properties    
  8.        0,    0, // enums/sets    
  9.        0,    0, // constructors    
  10.        0,       // flags    
  11.        2,       // signalCount   
  12. // signals: signature, parameters, type, tag, flags    
  13.       13,   12,   12,   12, 0x05,   
  14.       28,   12,   12,   12, 0x05,  
  15. // slots: signature, parameters, type, tag, flags    
  16.       36,   12,   12,   12, 0x0a,   
  17.       43,   12,   12,   12, 0x0a,  
  18. // methods: signature, parameters, type, tag, flags    
  19.       57,   12,   50,   12, 0x02,  
  20. // properties: name, type, flags    
  21.       71,   50, 0x43495103,  
  22. // properties: notify_signal_id    
  23.        0,  
  24.        0        // eod    
  25. };  
  26. static const char qt_meta_stringdata_EllipseItem[] = {   
  27.     "EllipseItem/0/0colorChanged()/0ready()/0"   
  28.     "try1()/0try2()/0QColor/0randomColor()/0"   
  29.     "color/0"   
  30. };  
 

 

从上面代码实例我们可以看到, QT的元对象编译器moc会识别声明在头文件中的宏Q_SIGNALS,Q_SLOTS, Q_PROPERTY, Q_PROPERTY。并以此做为依据,生成了元对象数据表。在这张元对象数据表中,我们已可以看到,moc根据头文件所声明的宏定义,识别出:

  • 两个信号:colorChanged(), ready();      (Q_SIGNALS)
  • 两个槽:    try1(), try2()                          (Q_SLOTS)
  • 五个方法,其中被标记为Q_INVOKABLE的方法randomColor()被记录在元对象字符串数组qt_meta_stringdata_EllipseItem中。  
  • 一个属性:color   (Q_PROPERTY)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值