龙空技术网

Qt的万能承载者—QObject

嵌入式小生 230

前言:

目前兄弟们对“类中的构造函数名字是______”大概比较关切,兄弟们都需要分析一些“类中的构造函数名字是______”的相关知识。那么小编也在网摘上收集了一些有关“类中的构造函数名字是______””的相关知识,希望我们能喜欢,姐妹们快快来了解一下吧!

一、QObject的重要知识

QObject是Qt对象模型的核心。这个模型的核心特性是一个强大的无缝对象通信机制,即信号和槽。可以使用connect()将信号连接到槽函数,并使用disconnect()破坏已经存在的连接。为了避免永不结束的通知循环,可以使用blockSignals()暂时阻塞信号。受保护的函数connectNotify()disconnectNotify()可以用于跟踪信号连接。

Qt中,以QObject为基础形成了一棵“对象树”,当使用另一个对象作为父对象创建QObject时,该对象将自动将自己添加到父对象的children()列表中。此后父对象拥有该对象的所有权,则会自动删除析构函数中的子元素。在开发中可以使用findChild()findChildren()根据名称和可选的类型查找子对象。

每个对象都有一个objectName(),可以通过相应的metaObject()找到它的类名(函数:QMetaObject::className())。在实际开发中可以使用inherits()函数确定对象的类是否继承了QObject继承层次结构中的另一个类。当一个对象被删除时,会发出destroyed()信号,通过这一点可以捕获此信号,避免对QObject进行悬挂引用。

二、QObject重要成员函数

本小节总结在开发中,QObject中常使用的成员函数和重要宏定义。

1、事件获取和处理API

/* 在此对象上安装事件筛选器filterObj */void QObject::installEventFilter(QObject *filterObj) /* 这个虚拟函数接收对象的事件,如果事件e被识别并处理,则返回true */bool QObject::event(QEvent *e)
2、对象的线程关联API
/* 返回对象所在的线程。 */QThread *QObject::thread() const      /* 更改对象及其子对象的线程关联性。如果一个对象有父对象,则不能移动该对象到另一个线程中 */void QObject::moveToThread(QThread *targetThread)     
3、获取子对象API
/* 返回该对象具有给定名称的所有可转换为类型T的子对象,如果没有此类对象,则返回一个空列表 */QList<T> findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const    /* 返回子对象列表 */const QObjectList & children() const
4、qobject_cast

函数原型如下:

T qobject_cast(QObject* object)T qobject_cast(const QObject* object)

如果对象类型为T(或子类),则将给定的对象转换为类型T;否则返回nullptr。如果对象是nullptr,那么它也将返回nullptr。

注意:类T必须继承(直接或间接)QObject并使用Q_OBJECT宏声明。

qobject_cast()函数的行为类似于标准c++dynamic_cast(),它的优点是不需要RTTI(Run-Time Type Identification-运行时类型识别)支持,并且可以跨动态库边界工作。

5、事件处理相关函数

//此虚函数用于接收对象的事件,如果事件e被识别和处理,则返回true。virtual bool event(QEvent *e)//如果此对象已作为被监视对象的事件过滤器安装,则过滤事件。virtual bool eventFilter(QObject *watched, QEvent *event)//从该对象中移除事件筛选器对象obj。void removeEventFilter(QObject *obj)//在对象上安装事件筛选器filterObjvoid installEventFilter(QObject *filterObj)
6、定时器相关函数
//启动计时器并返回计时器标识符int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer)//启动计时器并返回计时器标识符int startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)//使用定时器标识符id终止计时器void killTimer(int id)
7、重要宏定义Q_DISABLE_COPY(Class)禁止对给定类使用复制构造函数和赋值运算符。Q_DISABLE_COPY_MOVE(Class)

该宏用于禁用给定类的复制构造函数、赋值运算符、移动构造函数和移动赋值运算符,将Q_DISABLE_COPYQ_DISABLE_MOVE组合在一起。

Q_DISABLE_MOVE(Class 5.13)

禁止对给定类使用移动构造函数和移动赋值操作符。

Q_EMIT

当希望使用第三方信号/槽函数机制来使用Qt信号和槽函数时,可以使用此宏替代emit关键字来发出信号。

Q_ENUM(...)

这个宏用于向元对象系统注册一个枚举类型。该宏必须放在enum声明之后,且放在具有Q_OBJECTQ_GADGET宏的类中。对于命名空间,应该使用Q_ENUM_NS()。例如:

class MyClass : public QObject{    Q_OBJECTpublic:    MyClass(QObject *parent = nullptr);    ~MyClass();    enum Priority { High, Low, VeryHigh, VeryLow };    Q_ENUM(Priority)    void setPriority(Priority priority);    Priority priority() const;};
Q_ENUM_NS(...)

这个宏向元对象系统注册一个枚举类型。它必须放在enum声明之后,,且具有Q_NAMESPACE宏的名称空间中。与Q_ENUM相同,但在命名空间中。

Q_FLAG(...)

这个宏向元对象系统中注册一个单标记类型。它通常用于类定义中,以声明给定enum的值可以用作标志,并使用按位或运算符进行组合。对于命名空间,应该使用Q_FLAG_NS()。例如:

class QLibrary : public QObject{    Q_OBJECTpublic:    ...    enum LoadHint {        ResolveAllSymbolsHint = 0x01,        ExportExternalSymbolsHint = 0x02,        LoadArchiveMemberHint = 0x04    };    Q_DECLARE_FLAGS(LoadHints, LoadHint)    Q_FLAG(LoadHint)    ...}
Q_INTERFACES(...)

这个宏告诉Qt这个类实现了哪些接口。在宏定义在实现插件的时候使用。例如:

class BasicToolsPlugin : public QObject,                         public BrushInterface,                         public ShapeInterface,                         public FilterInterface{    Q_OBJECT    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.Examples.PlugAndPaint.BrushInterface" FILE "basictools.json")    Q_INTERFACES(BrushInterface ShapeInterface FilterInterface)public:    ...};
Q_NAMESPACE

Q_NAMESPACE宏用于将QMetaObject功能添加到名称空间。Q_NAMESPACE可以有Q_CLASSINFOQ_ENUM_NS、Q_FLAG_NS,但不能有Q_ENUMQ_FLAGQ_PROPERTYQ_INVOKABLE、信号或槽函数。

Q_NAMESPACE_EXPORT(EXPORT_MACRO)

该宏的工作原理与Q_NAMESPACE宏完全相同。但是,在名称空间中定义的外部staticMetaObject变量是用提供的EXPORT_MACRO限定符声明的。如果需要从动态库导出对象,该宏定义非常有用。

Q_OBJECT

Q_OBJECT宏必须出现在类定义的私有部分中,该类定义声明自己的信号和槽函数,或者使用Qt元对象系统提供的其他支持。

Q_PROPERTY(...)

此宏用于在继承QObject的类中声明属性。属性的行为类似于类数据成员,但它们具有可通过元对象系统访问的其他特性。如下代码:

Q_PROPERTY(type name           (READ getFunction [WRITE setFunction] |            MEMBER memberName [(READ getFunction | WRITE setFunction)])           [RESET resetFunction]           [NOTIFY notifySignal]           [REVISION int]           [DESIGNABLE bool]           [SCRIPTABLE bool]           [STORED bool]           [USER bool]           [CONSTANT]           [FINAL])
Q_SIGNAL

这是一个额外的宏,允许我们将单个函数标记为信号。当使用不支持信号或Q_SIGNALS组的第三方源代码解析器时,使用这个宏。

Q_SLOT

这是一个额外的宏,它允许将单个函数标记为槽函数。当使用不支持槽函数或Q_SLOT组的第三方源代码解析器时,使用这个宏。

三、信号和槽的连接机制注意事项

1、【自动连接(默认)】如果信号是在接收对象具有关联的线程中发出的,那么行为与直接连接相同。否则,行为与队列连接相同。

2、【直接连接】当信号发出时,槽函数被立即调用。槽函数在发射器的线程中执行,而发射器的线程不一定是接收器的线程。

3、【队列连接】当控制返回到接收方线程的事件循环时调用槽,槽函数在接收方的线程中执行。

4、【阻塞排队连接】槽被调用为排队连接,除非当前线程阻塞直到槽函数返回。

注意:使用该阻塞排队连接类型连接同一线程中的对象将导致死锁。

5、【唯一连接】与自动连接相同,但只在不复制现有连接的情况下才建立连接。也就是说,如果相同的信号已经为相同的对象连接到相同的槽,那么就不创建连接,并且connect()返回false

连接类型可以通过向connect()传递一个附加参数来指定。注意,如果事件循环运行在接收方的线程中,当发送方和接收方位于不同线程中时使用直接连接是不安全的,这与调用位于另一个线程中的对象上的函数是不安全的原因相同。

QObject::connect()本身是线程安全的。

对于队列连接,传递的参数必须是Qt元对象系统已知的类型,因为Qt需要复制参数,以便存储参数;如果参数类型不是Qt元对象系统已知的,使用队列连接,将获得错误提示信息,这时候则需要在创建连接之前,调用qRegisterMetaType()向元对象系统注册该数据类型。

四、线程关联性

在Qt中,QObject实例具有线程相关性,或者可以理解成QObject存在于某个线程中。当QObject接收到排队的信号或发布的事件时,槽函数或事件处理程序将在该对象所在的线程中运行,这一点很重要。

注意:如果一个QObject没有线程关联(也就是说,如果thread()返回0),或者如果它存在于一个没有运行事件循环的线程中,那么它就不能接收排队的信号或发布的事件。

默认情况下,QObject实例存在于创建它的线程中,在实际开发中可使用thread()查询对象的线程关联,并使用moveToThread()更改对象的线程关联。

注意:所有QObject必须与它们的父对象生活在同一个线程中。除此之外,还需要知道:

(1)如果涉及的两个QObject位于不同的线程中,setParent()将失败。

(2)当一个QObject被移动到另一个线程时,它的所有子线程也会被自动移动。

(3)如果QObject有一个父对象,moveToThread()将失败。

(4)如果QObject是在QThread::run()中创建的,它们不能成为QThread对象的子对象,因为QThread并不存在于调用QThread::run()的线程中。

QObject的父子关系必须通过传递一个指向子构造函数的指针或调用setParent()来设置。如果没有这个步骤,当调用moveToThread()时,对象的成员变量将保持在旧线程中。

『参考链接』:

【1】

【2】

标签: #类中的构造函数名字是______