QT特性-QObject、MOC、MOS
2015年1月7日
目标:Qt的元对象系统提供了QObject的基本功能,包含信号-槽,动态属性,运行时类型信息(RTTI)等。
原理:
QObject提供MOS的功能接口。
Q_OBJECT标识启用元对象系统。
MOC生成元对象系统的标准C++代码。
方法:
QObject::metaObject():返回相关的QMetaObject对象。
QMetaObject::className():返回当前类名(字符串)。
QObject::inherits():判断是否继承自指定类。
QObject::tr()/trUtf8():转码。
QObject::Property()/setProperty():动态属性。
QMetaObject::newInstance():创建新实例对象。
qobject_cast<type *>(obj):高级类型转换,不需要编译器支持RTTI,支持dll。
由于无Q_OBJECT宏时,无法使用QObject的特性,建议无论何时都使用Q_OBJECT。
QMetaObject::connectSlotsByName(this):自动连接机制,将this中槽函数与子对象建立连接。
QObject是所有Qt类的基类。
QObject在释放时会发出destroyed信号。
QObject会对所在线程的所有对象发布信号。
QObject存在对象树,父对象拥有子对象的所有权。
所有权是指父对象释放时,会先将子对象释放。
QObject具有一个objectName属性,可以通过setObjectName()设置。
QObject所属的类可以通过QMetaObject::className()获取。
如果对象树中相关对象被释放,则自动将相关指针设置为0。
示例:
qDebug()<<pListener->objectName ()<<pListener->metaObject()->className ();
所有QObject的子类,无法使用copy构造函数(将copy构造函数设置为私有,无法继承),因为信号槽模式,要求所有的QObject对象是唯一的。
需要使用copy的地方,只能使用指针代替。
如果使用了,会出现以下错误:
error: C2248: 'QObject::QObject' : cannot access privatemember declared in class 'QObject'
参考:http://qimo601.iteye.com/blog/1523936
目标:提供统一,跨编译器和平台的标准属性系统。
原理:由MOS提供。
方法:
Q_PROPERTY(type name
READ getFunction
[WRITE setFunction]
[RESET resetFunction]
[NOTIFY notifySignal]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
属性可以通过MOS读写。
属性可以通过MOS动态的从QObject添加、删除。
声明属性后,在QtCreator中,右击-》重构-》Generate missing Porperties会自动生成声明所有的函数和成员变量(成员变量变自动添加m_前缀)。
示例:
class QTask : public QObject
{
Q_OBJECT
Q_PROPERTY(int iTest READ getTest WRITEsetTest)
private:
int m_iTest;
public:
intgetTest() const
{
returnm_iTest;
}
public slots:
voidsetTest(int arg)
{
m_iTest = arg;
}
}
目标:在对象中动态添加、删除属性。
方法:setProperty(属性名,值)。
如果值有效,动态属性不存在,则添加动态属性。
如果值有效,属性存在,则改写。
如果值无效(QVariant()默认是无效值),则删除此动态属性,如果此属性不是动态的(显示声明的不是动态的),则无影响。
可以动态的添加属性或删除属性,动态属性只添加到QObject对象中,不影响MetaObject。并且也只能通过动态方法读写。
示例:
QTask *pT= new QTask;
pT->setTest (5);
qDebug()<<pT->getTest ();
int iTest= pT->property ("iTest").toInt ();
pT->setProperty ("abc",77);
int iDyn =pT->property ("abc").toInt ();
pT->setProperty("abc",QVariant());
int iDyn2= pT->property ("abc").toInt ();
目标:实现OS中事件的处理。
原理:接收OS事件,处理相应事件。
1) 事件与信号的区别:事件只向事件系统发送,由事件系统唯一分发;而信号则向所有QObject广播,由QObject决定处理。
2) 事件对应Windows中的消息,从OS中获取,然后发送到指定对象。事件循环在一个线程中唯一存在,同步(send)/异步(post)操作事件列表。信号也是同步(directconnect)或异步(queuedconnection)处理连接,如果异步,则等待时间片空闲时,发送异步信号队列。
方法:
1) 处理事件
事件(QEvent类的对象)是各种事件发生时,发送的通知信息。一般响应时需要重写基类的相应的响应函数。
QObject::event()是最顶级的事件处理函数,需要自己判断事件的类型。
使用指定的命令方式,moc可以分解将自动建立连接。只能建立在QObject及其子对象之间。
格式:on_ObjectName_Signal(params)。
操作函数:QMetaObject::connectSlotsByName(this)。
详见:qt-信号槽signalslot机制.docx
由于QObject提供了信号-槽机制,在消息循环中需要保持所有对象可用。为了避免在消息循环中引用被释放的指针,Qt对内存的管理引入了deleteLater()来代替delete(),用于保证需要释放的对象在消息循环结束后能够自动释放。
因此,在使用QObject时,需要注意,如果有进入消息循环的slot函数,或者在消息循环中使用的对象,则要使用deleteLater()。
参考:
http://stackoverflow.com/questions/4888189/how-delete-and-deletelater-works-wrt-to-signals-and-slots-in-qt
一般在释放时,会将指针置NULL(防止野指针),在使用deteteLater()后,不能直接赋值NULL,应该使用destroyed()信号的响应槽函数置NULL。
参考:
http://stackoverflow.com/questions/6095946/how-can-i-get-the-qobjectdeletelater-to-zero-the-object
示例:
信号
connect(m_pFw,SIGNAL(destroyed()),this,SLOT(nullWatcher()));
槽
void QMapFrameTask::nullWatcher()
{
m_pFw = NULL;
}
将qt的信号和槽转化为标准的C++代码。
MOC在Qt的bin目录下moc.exe。
使用方法
moc .h文件–o .moc文件
这里.moc文件就是标准的c++头文件。
在使用时,需要将所有使用信号和槽的头文件转化为.moc文件,然后将moc文件包含在头文件中(不要包含在cpp文件中)。
参见:qt-信号槽signalslot机制.docx