几个重要结论
QObject、线程和事件处理对象类图如下:
大多数Qt类的实现都采用”外部接口类+内部实现类“,即QAbc类作为接口给用户使用,但QAbc类的功能基本上在QAbcPrivate实现。
每个线程都以QThread实例表示,并且在内部拥有一个QThreadData来表示线程的基本数据。
每个线程维护了一个QPostEvent队列,用来保存待处理的事件(如鼠标、键盘以及用户事件),同时每个线程维护了一个QEventLoop栈,但只有栈顶的QEventLoop对象参与当前事件处理
Qt中重要的对象包括:QObject及其派生类对象、线程及其线程对象、事件及事件处理、signal/slot及其connection。
它们之间的关系如下:
**(1)QObject对象可以作为其他QObject的父亲,并其销毁时也会自动销毁所有的子对象。可以在父对象中获取子对象
(2)包括QThread对象在内,每个QObject对象都可以属于一个线程,但QObject与其父对象须属于同一线程,如某对象有父对象或是widget,则不能更换线程
(3)事件处理是基于线程,即如果某个QObject对象不属于线程(如何做到?),则该对象无法参与事件处理
(4)每个QObject对象都有数据结构包含了其所有signals有关的connections,而signal/slots的实现依赖于事件处理**
这里也有几个问题,可进一步思考:
问:QObject对象都是有对应的线程的,但是QThread对象并不属于它产生的线程,而是属于一开始创建QThread对象的线程。这会产生什么问题?
问:QThreadData为何会存在多个QEventLoop?
QObject
所有的Qt对象的基类是QObject,而QObject包含了其内部QObjectPrivate对象(在QObject的构造函数中初始化),QObject的需要的内部成员数据,基本上都放在QObjectPrivate里。Qt内部的类实现,往往会采用XXXClass + XXXClassPrivate机制,包括QObject及其许多派生类,都是如此。所有的XXXPrivate都派生于QObjectData,并提供了在内部QAbc和QAbcPrivate类中互相访问的快捷函数)。体可参见 Qt源码的Private Class实现介绍
QObjectPrivate及其基类QObjectData的关键成员介绍如下:
/* QObjectData */
// 当前QObject 对象的父对象
QObject *parent ;
// 当前QObject 对象的子对象
QObjectList children;
/* QObjectPrivate */
// 用户输入的数据
ExtraData *extraData ;
// 该对象所属的线程对象
QThreadData *threadData ;
// 该对象作为 sender的所有 connections
QObjectConnectionListVector *connectionLists ;
// 该对象作为 receiver的所有 connections
Connection *senders ;
// object currently activating the object
Sender *currentSender ;
从上面代码看,每个QObject都可以有parent和children,当用户在当前对象A构造函数中传入一个B作为父对象时,将当前对象A的parent成员生成B,并在B的children中加入A。当父对象销毁时,它所有的children也将被销毁。
QThreadData是该对象所属的线程对象,在QObject创建时在其构造函数中被设置。
QObjectConnectionListVector作为一个类,派生于QVector