Qt:QObject ゞ 浴缸里的玫瑰 2022-11-17 05:30 139阅读 0赞 QObject类是所有Qt对象的基类。 > 头文件: > > * `#include <QObject>` > > cmake: > > find_package(Qt6 COMPONENTS Core REQUIRED) > target_link_libraries(mytarget PRIVATE Qt6::Core) > > qmake: > > QT += core 注意:此类中的所有函数都是可重入的 注意:下列函数都是线程安全的: connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type) connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type) const connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type) connect(const QObject *sender, PointerToMemberFunction signal, Functor functor) connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type) disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method) disconnect(const char *signal, const QObject *receiver, const char *method) const disconnect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method) deleteLater() # 详细说明 # QObject是[Qt对象模型][Qt]的核心。该模型的中心特性是一种非常强大的无缝对象通信机制,叫做信号与槽。可以使用`connect()`将信号连接到槽,并使用`disconnect`销毁连接。为了避免永无止境的通知循环,可以使用`blockSignals()`临时阻止信号。受保护的函数`connectNotify()`和`disconnectNotify()`使跟踪连接成为可能。 QObjects在对象树中组织自己。当您使用另一个对象作为父对象创建QObject时,该对象会自动将其自身添加到父对象的`children()`列表中。父对象拥有该对象的所有权:即它将其析构函数中自动删除子对象。您可以按名称查找对象,也可以使用`findChild()`或`findChildren()`键入对象。 每个对象都有一个`objectName()`,并且可以通过相应的`metaObject()`找到其类名(QMetaObject :: className)。可以使用inherits()函数确定对象的类是否继承QObject继承层次结构中的另一个类。 删除对象后,它将发出一个destroyed()信号。您可以捕获此信号,以避免悬挂引用QObjects。 QObject可以通过event()接收事件,并过滤其他对象的事件。有关详细信息,请参见[installEventFilter()][installEventFilter]和[eventFilter()][eventFilter]。可以重新实现QObject的`childEvent()`函数来捕获子事件。 最后但并非最不重要的一点是,QObject在Qt中提供了基本的计时器支持。有关计时器的高级支持,请参见[QTimer][]。 请注意,对于实现信号、插槽或属性的任何对象,`Q_OBJECT`宏都是必需的。您还需要在源文件上运行[元对象编译器][Link 1]。我们强烈建议在QObject的所有子类中使用此宏,不管它们是否实际使用信号、插槽和属性,否则可能会导致某些函数表现出奇怪的行为。 所有Qt小部件都继承QObject。函数`isWidgeType()`返回一个对象是否是一个小部件。它比`qobject_cast<QWidget *>(obj)`或`obj->inherits("QWidget")`快得多。 一些QObject函数,例如children(),返回一个QObjectList。QObjectList是`QList<QObject*>`的typedef。 ## 线程亲和力 ## QObject示例被称为具有线程亲缘关系,或者它位于某个线程中。当QObject接收到[排队信号][Link 2]或者[已发布的事件][Link 3]时,槽函数或者事件处理程序将在对象所在的线程中运行。 注意:如果QObject没有线程关联(线程亲缘关系)(即`thread()`返回0),或者如果它位于没有运行事件循环的线程中,则它无法接收排队信号或已发布的事件, 默认情况下,QObject位于创建它的线程中。可以使用thread()查询对象的线程关联,并使用`meveToThread()`更改对象的线程管理 所有QObject必须与其父对象位于同一线程中,因此: * 如果涉及的两个QObject位于不同的线程中,则`setParent()`将失败。 * 当一个QObject移到另一个线程时,它的所有子对象也将被自动移动。 * 如果QObject具有父对象,则`moveToThread()`将失败。 * 如果QObject是在`QThread::run()`中创建的,则它们不能成为QThread对象的子对象,因为QThread不在调用QThread::run()的线程中。 注意:QObject的成员变量不会自动成为其子变量。必须通过向子构造函数传递指针或调用setParent()来设置父子关系。如果没有此步骤,调用moveToThread()时,对象的成员变量将保留在旧线程中。 ## 没有赋值构造函数或者赋值运算符 ## QObject既没有复制构造函数,也没有赋值运算符。这是设计使然。实际上,它们是在带有宏`Q_DISABLE_COPY`的私有部分中声明的。实际上,所有从QObject派生的Qt类(直接或间接)都使用这个宏来声明它们的复制构造函数和赋值操作符是私有的。推理可以在Qt对象模型页面上关于[Qt对象:Identity vs Value][Qt]的讨论中找到。 主要的结果是您应该使用指向QObject(或者指向您的QObject子类)的指针,否则您可能会试图使用您的QObject子类作为值。例如,如果没有复制构造函数,就不能使用QObject的子类作为存储在某个容器类中的值。必须存储指针。 ## 自动连接 ## Qt的元对象系统提供了一种在QObject子类以及其子类之间自动连接信号和槽的机制。只要使用合适的对象名称定义对象,并且槽函数遵循简单的命名约定,就可以在运行时通过`QMetaObject :: connectSlotsByName`执行此连接 uic生成调用此函数的代码,从而能够在使用Qt Designer创建的表单上的小部件之间执行自动连接。有关使用带自动连接更多信息Qt设计师[在给定的应用程序中使用一个设计UI文件][UI]中的部分Qt设计手册。 ## 动态特性 ## 从Qt4.2开始,可以在运行时向QObject实例添加动态属性,也可以从QObject实例中删除动态属性。动态属性不需要在编译时声明,但是它们提供了与静态属性相同的优点,并且使用相同的API进行操作—使用`property()`读取它们,使用`setProperty()`写入它们。 从qt4.3开始,Qt设计器支持动态属性,并且标准Qt小部件和用户创建的表单都可以被赋予动态属性。 ## 国际化 ## 所有QObject子类都支持Qt的翻译功能,从而可以将应用程序的用户界面翻译成不同的语言。 为了使用户可见的文本可翻译,必须将其包装在对[tr()][tr]函数的调用中。《[编写翻译的源代码][Link 4]》文档中对此进行了详细说明。 # 属性文档 # ## objectName:QString ## 此属性保存此对象的名称 您可以使用`findChild()`按名称(和类型)查找对象。您可以使用`findChildren()`查找一组对象。 qDebug("MyClass::setPrecision(): (%s) invalid precision %f", qPrintable(objectName()), newPrecision); 默认情况下,此属性包含一个空字符串。 * 访问函数: QString objectName() const void setObjectName(const QString &name) * 通知信号: void objectNameChanged(const QString &objectName) 注意:这是一个私人信号。它可以用于信号连接,但不能由用户发射。 另请参见metaObject()和QMetaObject :: className()。 # 相关非成员 # ## QObjectList ## `QList < QObject *>`的同义词 ## qobject\_cast ## > **template T qobject\_cast(QObject \*object)** > **template T qobject\_cast(const QObject \*object)** 如果对象是T类型(或子类),则返回给定对象转换为T类型;否则返回nullptr。如果object是nullptr,那么它也将返回nullptr。 类T必须(直接或间接地)继承QObject,并使用Q\_OBJECT宏声明。 一个类被认为是继承自己的。 例子: QObject *obj = new QTimer; // QTimer inherits QObject QTimer *timer = qobject_cast<QTimer *>(obj); // timer == (QObject *)obj QAbstractButton *button = qobject_cast<QAbstractButton *>(obj); // button == nullptr qobject\_cast()函数的行为类似于标准c++ dynamic\_cast(),其优点是它不需要RTTI支持,并且可以跨动态库边界工作。 qobject\_cast()也可以与接口一起使用;有关详细信息,请参见“[即插即用][Link 5]”示例。 警告:如果没有使用Q\_OBJECT宏声明T,这个函数的返回值是未定义的。 参见`QObject::inherits()`。 # 成员函数 # ## QObject ## > **QObject::QObject(QObject \*parent = nullptr)** 使用父对象parent构造一个对象。 对象的父级可以视为对象的所有者。例如,对话框是其包含的“确定”和“取消”按钮的父级。 父对象的析构函数将销毁所有子对象。 设置父nullptr对象以构造没有父对象的对象。如果对象是窗口小部件,它将成为顶层窗口。 注意:可以通过元对象系统和QML调用此函数。参见[Q\_INVOKABLE][Q_INVOKABLE]。 另请参见parent(),findChild()和findChildren()。 ## deleteLater ## > **\[slot\]void QObject::deleteLater()** 计划删除此对象。 当控制权返回事件循环时,该对象将被删除。如果在调用此函数时事件循环未运行((例如,在`QCoreApplication::exec()`之前对对象调用deleteLater()),则一旦启动事件循环,该对象将被删除。如果在主事件循环停止后调用deleteLater(),则不会删除该对象。从Qt4.8开始,如果对没有运行事件循环的线程中的对象调用deleteLater(),则该对象将在线程完成时被销毁。 请注意,进入和离开新的事件循环(例如,通过打开模式对话框)将不会执行延迟删除。对于要删除的对象,控件必须返回到调用deleteLater()的事件循环。这不适用于先前的嵌套事件循环仍在运行时删除的对象:新的嵌套事件循环开始后,Qt事件循环将删除这些对象。 注意:多次调用此函数是安全的;当传递第一个延迟删除事件时,对象的所有挂起事件都将从事件队列中删除。 注意:此函数是线程安全的。 另请参见destroyed()和[QPointer][]。 ## destroyed ## > **\[signal\]void QObject::destroyed(QObject \*obj = nullptr)** 这个信号在对象obj被销毁之前立即发出,在任何QPointer的实例被通知之后发出,并且不能被阻塞。 所有对象的子对象在这个信号发出后立即被销毁。 另请参见`deleteLater()`和`QPointer`。 ## objectNameChanged ## > **\[private signal\]void QObject::objectNameChanged(const QString &objectName)** 此信号在对象名称更改后发出。新对象名称作为objectName传递。 注意:这是私人信号。它可以用于信号连接,但不能由用户发出。 注意:属性objectName的通知信号。 另请参见`QObject::objectName`。 ## ~QObject ## > **\[virtual\]QObject::~QObject()** 销毁对象,删除其所有的子对象 所有进出该对象的信号都将自动端口连接,对象的任何挂起的已发布事件都将从事件队列中删除。然而,使用deleteLater()通常比直接删除QObject子类更安全。 警告:删除所有子对象。如果这些对象中的任何一个在堆栈中或全局的,你的程序迟早会崩溃。我们不建议在父对象之外保存指向子对象的指针。如果您仍然这样做,destroy()信号将为您提供一个机会来检测对象何时被销毁。 警告:在等待交付的挂起事件中删除QObject可能导致崩溃。如果QObject存在于与当前正在执行的线程不同的线程中,则不能直接删除它。使用deleteLater()代替,它将导致事件循环在所有挂起的事件都交付给对象之后删除对象。 参见`deleteLater()`。 ## blockSignals ## > **bool QObject::blockSignals(bool block)** 如果block为true,则阻塞此对象发出的信号(即,发出信号将不会调用与其连接的任何对象)。如果block为false,则不会发生这种阻塞。 返回值是signalsBlocked()的前一个值。 请注意,即使该对象的信号已被阻止,也会发出destroy()信号。 被阻止时发出的信号不会被缓冲。 另请参见signalsBlocked()和QSignalBlocker。 ## childEvent ## > **\[virtual protected\]void QObject::childEvent(QChildEvent `*`event)** 可以在子类中重新实现此事件处理程序以接收子事件。事件在event参数中传递 添加或者删除子对象时,会将`QEvent::ChildAdded`和`QEvent::ChildRemoved`事件发送到对象。在这两种情况下,在这两种情况下,您只能依赖于子对象是QObject,或者如果isWidgetType()返回true,则依赖于QWidget。(这是因为在ChildAdded情况下,子级尚未完全构造,而在ChildRemoved情况下,子级可能已经被破坏)。 当polished子对象或添加polished子对象时,会将QEvent::ChildPolished事件发送到小部件。如果您收到一个子事件,子事件的构造通常是完成的。但是,这并不能保证,在执行小部件的构造函数期间可能会传递多个polish事件。 对于每个子小部件,您将收到一个ChildAdded事件、零个或多个ChildPolished事件和一个ChildRemoved事件。 如果在添加子对象后立即删除该子对象,则会忽略ChildPolished事件。如果在构造和销毁过程中对一个子级进行了多次polish,那么您可能会收到同一个子级的多个子级polish事件,每次都使用不同的虚拟表。 另请参见event()。 ## children ## > **const QObjectList &QObject::children() const** typedef QList<QObject*> QObjectList; 返回子对象的列表。QObjectList类在头文件`<QObject>`中定义如下: typedef QList<QObject*> QObjectList; 添加的第一个子对象是列表中的第一个对象,添加的最后一个子对象是列表中的最后一个对象,也就是说,新的子对象被追加到列表的末尾。 注意,当QWidget子节点被提高或降低时,列表顺序会发生变化。被抛出的小部件将成为列表中的最后一个对象,被降低的小部件将成为列表中的第一个对象。 请参阅findChild()、findChildren()、parent()和setParent()。 ## connect ## > **\[static\]QMetaObject::Connection QObject::connect(const QObject `*`sender, const char `*`signal, const QObject `*`receiver, const char `*`method, Qt::ConnectionType type = Qt::AutoConnection)** 创建从发送方对象中的信号到接收方对象中的方法的给定类型的连接。返回连接的句柄,稍后可用于断开连接。 指定信号和方法时,必须使用SIGNAL()和SLOT()宏,例如: QLabel *label = new QLabel; QScrollBar *scrollBar = new QScrollBar; QObject::connect(scrollBar, SIGNAL(valueChanged(int)), label, SLOT(setNum(int))); 此示例确保标签始终显示当前滚动条值。注意,signal和slots参数不能包含任何变量名,只能包含类型。例如,以下情况不起作用,返回false: // WRONG QObject::connect(scrollBar, SIGNAL(valueChanged(int value)), label, SLOT(setNum(int value))); 一个信号也可以连接到另一个信号: class MyWidget : public QWidget { Q_OBJECT public: MyWidget(); signals: void buttonClicked(); private: QPushButton *myButton; }; MyWidget::MyWidget() { myButton = new QPushButton(this); connect(myButton, SIGNAL(clicked()), this, SIGNAL(buttonClicked())); } 在本例中,MyWidget构造函数传递来自私有成员变量的信号,并使其在与MyWidget相关的名称下可用。 一个信号可以连接到许多插槽和信号。许多信号可以连接到一个插槽。 如果一个信号连接到多个插槽,则在发出信号时,这些插槽将按连接的相同顺序激活。 如果函数成功地将信号连接到插槽,则返回一个QMetaObject::Connection,该连接表示连接的句柄。如果连接句柄无法创建连接,例如,如果QObject无法验证信号或方法的存在,或者它们的签名不兼容,则连接句柄将无效。您可以通过将句柄强制转换为布尔值来检查它是否有效。 默认情况下,为每个连接发出一个信号;为重复连接发出两个信号。您可以通过一个disconnect()调用中断所有这些连接。如果传递Qt::UniqueConnection类型,则仅当它不是重复连接时才会建立连接。如果已经有一个重复的(完全相同的信号到相同对象上完全相同的插槽),连接将失败,connect将返回一个无效的QMetaObject::connection。 注意:Qt::UniqueConnections不适用于lambda、非成员函数和functor;它们只适用于连接到成员函数。 可选参数“type”描述要建立的连接类型。具体来说,它确定特定的信号是立即发送到插槽,还是排队等待稍后的时间发送。如果信号是排队的,参数必须是Qt元对象系统已知的类型,因为Qt需要复制参数,将它们存储在后台的事件中。如果尝试使用队列连接并获取错误消息 QObject::connect: Cannot queue arguments of type 'MyType' (Make sure 'MyType' is registered using qRegisterMetaType().) 在建立连接之前,调用qRegisterMetaType()注册数据类型。 注意:这个函数是线程安全的。 > **\[static\] > QMetaObject::Connection QObject::connect(const QObject `*`sender, const QMetaMethod &signal, const QObject `*`receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection)** 创建从发送方对象中的信号到接收方对象中的方法的给定类型的连接。返回连接的句柄,可用于稍后断开连接。 如果连接句柄不能创建连接,那么它将是无效的,例如,参数无效。您可以通过将QMetaObject::Connection转换为bool来检查它是否有效。 这个函数与connect函数的工作方式相同(const QObject \*sender, const char \*signal, const QObject \*receiver, const char \*method, Qt::ConnectionType type),但它使用QMetaMethod来指定信号和方法。 > \*\*QMetaObject::Connection QObject::connect(const QObject `*`sender, const char `*`signal, const char `*`method, Qt::ConnectionType type = Qt::AutoConnection) const 此函数重载connect()。 将来自发送方对象的信号连接到此对象的方法。 相当于`connect(sender, signal, this, method, type).` 你建立的每一个连接都会发出一个信号,所以重复的连接会发出两个信号。您可以使用disconnect()断开连接。 注意:这个函数是线程安全的。 参见 disconnect(). > **\[static\] > template `<typename PointerToMemberFunction>` QMetaObject::Connection QObject::connect(const QObject `*`sender, PointerToMemberFunction signal, const QObject `*`receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)** 这个函数重载connect()。 创建从发送方对象中的信号到接收方对象中的方法的给定类型的连接。返回连接的句柄,可用于稍后断开连接。 信号必须是在头文件中声明为信号的函数。槽函数可以是任何可以连接到信号的成员函数。如果信号的参数至少与槽的参数一样多,则可以将槽连接到给定信号,并且在信号和槽中对应参数的类型之间存在隐式转换。 例子: QLabel *label = new QLabel; QLineEdit *lineEdit = new QLineEdit; QObject::connect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText); 此示例确保标签始终显示当前行的编辑文本。 一个信号可以连接到许多插槽和信号。许多信号可以连接到一个槽。 如果一个信号被连接到几个插槽,当信号被发射时,插槽被激活的顺序与建立连接的顺序相同 如果成功地将信号连接到插槽,函数将返回一个连接句柄。如果连接句柄不能创建连接,那么它将是无效的,例如,如果QObject无法验证signal的存在(如果它没有被声明为signal),您可以通过将其转换为bool来检查QMetaObject::Connection是否有效。 默认情况下,你建立的每一个连接都会发出一个信号;重复连接会发出两个信号。您可以通过一个disconnect()调用断开所有这些连接。如果您传递Qt::UniqueConnection类型,那么只有当它不是一个副本时才会建立连接。如果已经有一个副本(相同对象上相同槽的完全相同的信号),连接将失败,连接将返回一个无效的QMetaObject::连接。 可选参数“type”描述要建立的连接类型。具体来说,它确定特定的信号是立即发送到插槽,还是排队等待稍后的时间发送。如果信号是排队的,参数必须是Qt元对象系统已知的类型,因为Qt需要复制参数,将它们存储在后台的事件中。如果尝试使用队列连接并获取错误消息 QObject::connect: Cannot queue arguments of type 'MyType' (Make sure 'MyType' is registered using qRegisterMetaType().) 确保使用Q\_DECLARE\_METATYPE声明参数类型 可以在qOverload的帮助下解析重载函数。 注意:这个函数是线程安全的。 > **\[static\] > template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject `*`sender, PointerToMemberFunction signal, Functor functor)** 此函数重载connect()。 创建从sender对象中的信号到functor的连接,并返回连接的句柄 信号必须是在标头中声明为信号的函数。slot函数可以是任何可以连接到信号的函数或函子。如果信号的参数至少与slot函数一样多,那么slot函数可以连接到给定的信号。信号和插槽中相应参数的类型之间必须存在隐式转换。 例子: void someFunction(); QPushButton *button = new QPushButton; QObject::connect(button, &QPushButton::clicked, someFunction); 也可以使用Lambda表达式: QByteArray page = ...; QTcpSocket *socket = new QTcpSocket; socket->connectToHost("qt-project.org", 80); QObject::connect(socket, &QTcpSocket::connected, [=] () { socket->write("GET " + page + "\r\n"); }); 如果发送者被销毁,连接将自动断开。但是,您应该注意,在发出信号时,函数内使用的任何对象仍然是活的。 可以在qOverload的帮助下解析重载函数。 注意:这个函数是线程安全的。 > \*\*\[static, since 5.2\]template <typename PointerToMemberFunction, typename Functor> QMetaObject::Connection QObject::connect(const QObject `*`sender, PointerToMemberFunction signal, const QObject `*`context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection) 这个函数重载connect()。 创建一个给定类型的连接,从signal in sender对象到functor,放置在上下文的特定事件循环中,并返回该连接的句柄。 注意:Qt::UniqueConnections不工作的lambdas,非成员函数和functor;它们只适用于连接到成员函数。 信号必须是在头文件中声明为信号的函数。槽函数可以是任何可以连接到信号的函数或函子。如果给定信号具有至少与槽函数相同的参数,则槽函数可以连接到给定信号。信号和槽中相应参数的类型之间必须存在隐式转换。 例子: void someFunction(); QPushButton *button = new QPushButton; QObject::connect(button, &QPushButton::clicked, this, someFunction, Qt::QueuedConnection); 也可以使用Lambda表达式: QByteArray page = ...; QTcpSocket *socket = new QTcpSocket; socket->connectToHost("qt-project.org", 80); QObject::connect(socket, &QTcpSocket::connected, this, [=] () { socket->write("GET " + page + "\r\n"); }, Qt::AutoConnection); 如果发送方或上下文被销毁,连接将自动断开。但是,您应该注意,在发出信号时,函数内使用的任何对象仍然是活的。 可以在qOverload的帮助下解析重载函数。 注意:这个函数是线程安全的。 这个函数是在Qt 5.2中引入的。 ## connectNotify ## > **\[virtual protected, since 5.0\] > void QObject::connectNotify(const QMetaMethod &signal)** 当有东西连接到这个对象中的signal时,这个虚函数被调用。 如果你想比较信号和特定信号,你可以使用QMetaMethod::fromSignal(),如下所示: if (signal == QMetaMethod::fromSignal(&MyObject::valueChanged)) { // signal is valueChanged } 警告:此函数违反了面向对象的模块化原则。但是,当您需要仅在某些东西连接到信号时才执行昂贵的初始化时,它可能很有用。 警告:此函数是从执行连接的线程调用的,该线程可能与此对象所在的线程不同。 这个函数是在qt5.0中引入的。 另请参见connect()和disconnectNotify()。 ## customEvent ## > **\[virtual protected\] > void QObject::customEvent(QEvent `*`event)** 可以在子类中重新实现此事件处理程序以接收自定义事件。自定义事件是用户定义的事件,其类型值至少与QEvent:: type enum的QEvent::User项一样大,通常是QEvent的子类。事件在event参数中传递。 另请参阅event()和QEvent。 ## disconnect ## > **\[static\]bool QObject::disconnect(const QObject `*`sender, const char `*`signal, const QObject `*`receiver, const char `*`method)** 断开对象发送器中的信号与对象接收器中的方法的连接。如果成功断开连接,返回true;否则返回false。 当涉及的任何一个对象被销毁时,信号槽连接被删除。 disconnect()通常以三种方式使用,如下面的示例所示。 (1). 断开连接到对象信号的所有东西: disconnect(myObject, nullptr, nullptr, nullptr); 等效于非静态重载函数 myObject->disconnect(); (2). 断开连接到特定信号的所有东西: disconnect(myObject, SIGNAL(mySignal()), nullptr, nullptr); 等效于非静态重载函数 myObject->disconnect(SIGNAL(mySignal())); (3). 断开特定的接收器: disconnect(myObject, nullptr, myReceiver, nullptr); 等效于非静态重载函数 myObject->disconnect(myReceiver); nullptr可以用作通配符,分别表示“任何信号”、“任何接收对象”或“接收对象中的任何槽”。 发送者可能永远不会是nullptr。(你不能在一个调用中断开多个对象的信号。) 如果信号为nullptr,它将断开接收器和方法与任何信号的连接。如果不是,则只断开指定信号。 如果接收器是nullptr,它将断开任何连接到信号的连接。否则,接收器以外的其他对象中的插槽不会断开连接。 如果方法是nullptr,它将断开连接到接收器的任何东西。如果不是,只有名为method的插槽将被断开连接,而其他所有插槽将被保留。如果未指定receiver,则该方法必须为nullptr,因此不能断开所有对象上指定的插槽。 注意:断开所有信号槽连接也会断开QObject::destroyed()信号,如果它已连接。这样做会对依赖此信号清理资源的类产生不利影响。建议只断开由应用程序代码连接的特定信号。 注意:这个函数是线程安全的。 参见 connect(). > **bool QObject::disconnect(const QObject `*`sender, const QMetaMethod &signal, const QObject `*`receiver, const QMetaMethod &method)** 断开对象发送器中的信号与对象接收器中的方法的连接。如果成功断开连接,返回true;否则返回false。 这个函数提供了与disconnect(const QObject \*sender, const char \*signal, const QObject \*receiver, const char \*method)相同的可能性,但使用qmetamemethod表示要断开连接的信号和方法。 此外,如果: * signal不是sender类或其父类之一的成员。 * 方法不是receiver类或其父类的成员。 * 信号实例不代表信号。 QMetaMethod() 可以用作通配符,表示“任何信号”或“接收对象中的任何槽”。同样,nullptr也可以用于含义为“任何接收对象”的receiver。在这种情况下,method也应该是QMetaMethod() 。sender参数永远不应该是nullptr。 注意:断开所有信号槽连接也会断开QObject::destroyed()信号,如果它已连接。这样做会对依赖此信号清理资源的类产生不利影响。建议只断开由应用程序代码连接的特定信号。 > **bool QObject::disconnect(const char `*`signal = nullptr, const QObject `*`receiver = nullptr, const char `*`method = nullptr) const** 这个函数重载disconnect()。 从接收机的方法断开信号。 当涉及的任何一个对象被销毁时,信号槽连接被删除。 注意:断开所有信号槽连接也会断开QObject::destroyed()信号,如果它已连接。这样做会对依赖此信号清理资源的类产生不利影响。建议只断开由应用程序代码连接的特定信号。 注意:这个函数是线程安全的。 > **bool QObject::disconnect(const QObject `*`receiver, const char `*`method = nullptr) const** 这个函数重载disconnect()。 从receiver的方法断开此对象中的所有信号。 当涉及的任何一个对象被销毁时,信号槽连接被删除。 > **\[static\] > bool QObject::disconnect(const QMetaObject::Connection &connection)** 断开连接。 如果连接无效或已经断开连接,则什么也不做并返回false。 > **\[static\] > template `<typename PointerToMemberFunction>` > bool QObject::disconnect(const QObject `*`sender, PointerToMemberFunction signal, const QObject `*`receiver, PointerToMemberFunction method)** 这个函数重载disconnect()。 断开对象发送器中的信号与对象接收器中的方法的连接。如果成功断开连接,返回true;否则返回false。 当涉及的任何一个对象被销毁时,信号槽连接被删除。 disconnect()通常以4种方式使用,如下面的示例所示。 (1). 断开连接到对象信号的所有东西: disconnect(myObject, nullptr, nullptr, nullptr); (2). 断开连接到特定信号的所有东西: disconnect(myObject, &MyObject::mySignal(), nullptr, nullptr); (3). 断开特定的接收器: disconnect(myObject, nullptr, myReceiver, nullptr); (4). 断开从一个特定信号到一个特定槽的连接 QObject::disconnect(lineEdit, &QLineEdit::textChanged, label, &QLabel::setText); nullptr可以用作通配符,分别表示“任何信号”、“任何接收对象”或“接收对象中的任何槽”。 发送者可能永远不会是nullptr。(你不能在一个调用中断开多个对象的信号。) 如果信号为nullptr,它将断开接收器和方法与任何信号的连接。如果不是,则只断开指定信号。 如果接收器是nullptr,它将断开任何连接到信号的连接。如果不是,则只断开指定接收器中的插槽。使用非空接收器的disconnect()也会断开以接收器作为上下文对象连接的槽函数。 如果方法是nullptr,它将断开连接到接收器的任何东西。如果不是,只有名为method的插槽将被断开连接,而其他所有插槽将被保留。如果未指定receiver,则该方法必须为nullptr,因此不能断开所有对象上指定的插槽。 注意:不可能使用这个重载来断开连接到函子或lambda表达式的信号。这是因为不可能比较它们。相反,使用接受`QMetaObject::Connection`的重载 注意:这个函数是线程安全的。 ## disconnectNotify ## > **\[virtual protected, since 5.0\] > void QObject::disconnectNotify(const QMetaMethod &signal)** 这个虚函数在与这个对象中的信号断开连接时被调用。 有关如何比较信号与特定信号的示例,请参阅connectNotify()。 如果所有信号都从这个对象断开(例如,disconnect()的信号参数是nullptr), disconnectNotify()只被调用一次,并且信号将是无效的QMetaMethod (QMetaMethod::isValid()返回false)。 警告:这个函数违反了模块化的面向对象原则。然而,它可能有助于优化对昂贵资源的访问。 警告:这个函数是从执行断开连接的线程调用的,这个线程可能与这个对象所在的线程不同。这个函数也可以在QObject内部互斥锁锁定的情况下调用。因此,不允许从重新实现中重新输入任何QObject函数,并且如果在重新实现中锁定了一个互斥量,请确保不要使用在其他地方持有的互斥量调用QObject函数,否则将导致死锁。 这个函数是在Qt 5.0中引入的。 参见disconnect()和connectNotify()。 ## dumpObjectInfo ## > **void QObject::dumpObjectInfo() const** 将此对象的信号连接等信息转储到调试输出。 注意:在Qt 5.9之前,这个函数不是const函数。 参见dumpObjectTree()。 ## dumpObjectTree ## > **void QObject::dumpObjectTree() const** 将子节点树转储到调试输出。 注意:在Qt 5.9之前,这个函数不是const函数。 参见dumpObjectInfo()。 ## dynamicPropertyNames ## > **QList`<QByteArray>`QObject::dynamicPropertyNames() const** 返回使用setProperty()动态添加到对象中的所有属性的名称。 ## event ## > **\[virtual\] > bool QObject::event(QEvent`*`e)** 这个虚函数将事件接收到一个对象,如果事件e被识别并处理,则返回true。 可以重新实现event()函数来定制对象的行为。 确保为所有未处理的事件调用父事件类实现。 例子: class MyClass : public QWidget { Q_OBJECT public: MyClass(QWidget *parent = nullptr); ~MyClass(); bool event(QEvent* ev) override { if (ev->type() == QEvent::PolishRequest) { // overwrite handling of PolishRequest if any doThings(); return true; } else if (ev->type() == QEvent::Show) { // complement handling of Show if any doThings2(); QWidget::event(ev); return true; } // Make sure the rest of events are handled return QWidget::event(ev); } }; 另请参阅installEventFilter()、timerEvent()、QCoreApplication::sendEvent()和QCoreApplication::postEvent()。 ## eventFilter ## > \*\*\[virtual\]bool QObject::eventFilter(QObject `*`watched, QEvent `*`event) 如果此对象已被安装为被监视对象的事件过滤器,则筛选事件。 在重新实现此功能时,如果要过滤事件退出,即停止进一步处理,返回true;否则返回false。 例子: class MainWindow : public QMainWindow { public: MainWindow(); protected: bool eventFilter(QObject *obj, QEvent *ev) override; private: QTextEdit *textEdit; }; MainWindow::MainWindow() { textEdit = new QTextEdit; setCentralWidget(textEdit); textEdit->installEventFilter(this); } bool MainWindow::eventFilter(QObject *obj, QEvent *event) { if (obj == textEdit) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); qDebug() << "Ate key press" << keyEvent->key(); return true; } else { return false; } } else { // pass the event on to the parent class return QMainWindow::eventFilter(obj, event); } } 注意,在上面的示例中,未处理的事件被传递给基类的eventFilter()函数,因为基类可能为了自己的内部目的重新实现了eventFilter()。 有些事件,例如QEvent::ShortcutOverride必须被显式地接受(通过调用accept()),以防止传播。 警告:如果你删除这个函数中的receiver对象,请确保返回true。否则,Qt将把事件转发给被删除的对象,程序可能会崩溃。 参见installEventFilter()。 ## findChild ## > **template `<typename T>` T > QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const** 返回该对象的子对象,该子对象可以转换为类型T,称为name,如果没有这样的对象,则返回nullptr。忽略name参数将导致匹配所有对象名称。搜索是递归执行的,除非options指定了FindDirectChildrenOnly选项。 如果有多个子节点与搜索匹配,则返回最直接的祖先。如果有几个直接祖先,则没有定义将返回哪个祖先。在这种情况下,应该使用findChildren()。 这个例子返回了parentWidget的一个名为“button1”的子QPushButton,即使这个按钮不是父QPushButton的直接子qbutton1: QPushButton *button = parentWidget->findChild<QPushButton *>("button1"); 这个例子返回了parentWidget的QListWidget子组件: QListWidget *list = parentWidget->findChild<QListWidget *>(); 这个例子返回了parentWidget(它的直接父类)的一个名为“button1”的子QPushButton: QPushButton *button = parentWidget->findChild<QPushButton *>("button1", Qt::FindDirectChildrenOnly); 这个例子返回了parentWidget(它的直接父类)的QListWidget子类: QListWidget *list = parentWidget->findChild<QListWidget *>(QString(), Qt::FindDirectChildrenOnly); 另请参见: findChildren(). ## findChildren ## > \*\*template`<typename T>` > QList`<T>`QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const 返回该对象具有给定名称的所有子对象,这些子对象可以被转换为类型T,如果没有这样的对象,则返回一个空列表。忽略name参数将导致匹配所有对象名称。搜索是递归执行的,除非options指定了FindDirectChildrenOnly选项。 下面的例子展示了如何查找指定的名为widgetname的parentWidget的子QWidgets列表: QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname"); 这个例子返回了parentWidget的所有子QPushButtons : QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>(); 这个例子返回所有的QPushButtons ,它们都是parentWidget的直接子代: QList<QPushButton *> childButtons = parentWidget.findChildren<QPushButton *>(QString(), Qt::FindDirectChildrenOnly); 另请参见: findChild(). > **\[since 5.0\] > template `<typename T>`QList`<T>`QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const** 这个函数重载findChildren()。 返回该对象的子对象,这些子对象可以被强制转换为类型T,并且其名称与正则表达式re匹配,如果没有这样的对象,则返回一个空列表。搜索是递归执行的,除非options指定了FindDirectChildrenOnly选项。 这个函数是在Qt 5.0中引入的。 ## inherits ## > **bool QObject::inherits(const char `*`className) const** 如果该对象是继承className的类的实例或继承className的QObject子类的实例,则返回true;否则返回false。 类被认为是继承自己。 例子: QTimer *timer = new QTimer; // QTimer inherits QObject timer->inherits("QTimer"); // returns true timer->inherits("QObject"); // returns true timer->inherits("QAbstractButton"); // returns false // QVBoxLayout inherits QObject and QLayoutItem QVBoxLayout *layout = new QVBoxLayout; layout->inherits("QObject"); // returns true layout->inherits("QLayoutItem"); // returns true (even though QLayoutItem is not a QObject) 如果需要确定一个对象是否是用于强制转换的特定类的实例,请考虑使用`qobject_cast<Type *>(object)`代替。 另请参见`metaObject()`和`qobject_cast().`。 ## installEventFilter ## > **void QObject::installEventFilter(QObject `*`filterObj)** 在此对象上安装一个事件过滤器filterObj。例如: monitoredObj->installEventFilter(filterObj); 事件过滤器是接收发送到此对象的所有事件的对象。筛选器可以停止事件或将其转发给此对象。事件过滤器filterObj通过其eventFilter()函数接收事件。eventFilter()函数必须返回true,如果事件应该被过滤,(即停止);否则它必须返回false。 如果在单个对象上安装了多个事件筛选器,则最后安装的筛选器将首先被激活。 这里有一个KeyPressEater类,它会吃掉被监控对象的按键: class KeyPressEater : public QObject { Q_OBJECT ... protected: bool eventFilter(QObject *obj, QEvent *event) override; }; bool KeyPressEater::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event); qDebug("Ate key press %d", keyEvent->key()); return true; } else { // standard event processing return QObject::eventFilter(obj, event); } } 下面是如何在两个小部件上安装它: KeyPressEater *keyPressEater = new KeyPressEater(this); QPushButton *pushButton = new QPushButton(this); QListView *listView = new QListView(this); pushButton->installEventFilter(keyPressEater); listView->installEventFilter(keyPressEater); 例如,QShortcut类使用这种技术来拦截快捷键的按下。 警告:如果你删除了eventFilter()函数中的receiver对象,请确保返回true。如果你返回false, Qt发送事件给被删除的对象,程序将崩溃。 注意,过滤对象必须与此对象在同一个线程中。如果filterObj在不同的线程中,这个函数什么也不做。如果filterObj或此对象在调用此函数后移动到不同的线程,则不会调用事件筛选器,直到这两个对象再次具有相同的线程相关性(它不会被删除)。 另请参阅removeEventFilter()、eventFilter()和event() ## isSignalConnected ## > **\[protected, since 5.0\]bool QObject::isSignalConnected(const QMetaMethod &signal) const** 如果信号至少连接到一个接收器,则返回true,否则返回false。 signal必须是该对象的signal成员,否则行为未定义。 static const QMetaMethod valueChangedSignal = QMetaMethod::fromSignal(&MyObject::valueChanged); if (isSignalConnected(valueChangedSignal)) { QByteArray data; data = get_the_value(); // expensive operation emit valueChanged(data); } 正如上面的代码片段所示,您可以使用这个函数来避免发出无人监听的信号。 警告:这个函数违反了模块化的面向对象原则。然而,当您需要执行昂贵的初始化时,它可能会很有用,只有当某些东西连接到一个信号时。 这个函数是在Qt 5.0中引入的。 ## isWidgetType ## > **bool QObject::isWidgetType() const** 如果对象是小部件则返回true;否则返回false。 调用这个函数等价于调用inherits(“QWidget”),只不过它要快得多。 ## isWindowType ## > **bool QObject::isWindowType() const** 如果对象是窗口则返回true;否则返回false。 调用这个函数等价于调用inherits(“QWindow”),只不过它要快得多。 ## killTimer ## > **void QObject::killTimer(int id)** 杀死带有定时器标识符id的定时器。 当一个计时器事件启动时,由startTimer()返回计时器标识符。 请参阅timerEvent()和startTimer()。 ## metaObject ## > **\[virtual\] > const QMetaObject `*`QObject::metaObject() const** 返回这个对象元对象的指针。 一个元对象包含了一个继承QObject的类的信息,例如类名,超类名,属性,信号和槽。每个包含Q\_OBJECT宏的QObject子类都有一个元对象。 信号/插槽连接机制和属性系统需要元对象信息。inherited()函数也使用了元对象。 如果没有指向实际对象实例的指针,但仍然希望访问类的元对象,则可以使用`staticMetaObject`。 例子: QObject *obj = new QPushButton; obj->metaObject()->className(); // returns "QPushButton" QPushButton::staticMetaObject.className(); // returns "QPushButton" ## moveToThread ## > **void QObject::moveToThread(QThread `*`targetThread)** 更改此对象及其子对象的线程关联性。如果对象有父对象,则无法移动该对象。事件处理将在targetThread中继续进行。 要将一个对象移动到主线程,可以使用QApplication::instance()来检索当前应用程序的指针,然后使用QApplication::thread()来检索应用程序所在的线程。例如: myObject->moveToThread(QApplication::instance()->thread()); 如果targetThread为nullptr,则此对象及其子对象的所有事件处理都将停止,因为它们不再与任何线程相关联。 注意,该对象的所有活动计时器将被重置。计时器首先在当前线程中停止,然后在targetThread中重新启动(以相同的时间间隔)。因此,不断地在线程之间移动对象可能无限期地延迟计时器事件。 一个QEvent::ThreadChange事件在线程关联性改变之前被发送到这个对象。您可以处理此事件来执行任何特殊处理。请注意,任何发布到该对象的新事件都将在targetThread中处理,前提是它不是nullptr:当它是nullptr时,对该对象及其子对象的事件处理都不会发生,因为它们不再与任何线程相关联。 警告:这个函数不是线程安全的;当前线程必须与当前线程关联相同。换句话说,这个函数只能将对象从当前线程“推”到另一个线程,而不能将对象从任何任意线程“拉”到当前线程。但是,这条规则有一个例外:没有线程关联的对象可以被“拉”到当前线程。 moveToThread里执行的函数没执行完,你是无法通过quit来结束的,必须使用第一种方法:最歹毒的一招mthread->terminate()强制退出。 参见thread()。 ### 例子1 ### /*! * \file main.cpp * * Copyright (C) 2010, dbzhang800 * All rights reserved. * */ #include <QtCore/QCoreApplication> #include <QtCore/QObject> #include <QtCore/QThread> #include <QtCore/QDebug> class Dummy:public QObject { Q_OBJECT public: Dummy(QObject* parent=):QObject(parent) { } public slots: void emitsig() { emit sig(); } signals: void sig(); }; class Object:public QObject { Q_OBJECT public: Object(){ } public slots: void slot() { qDebug()<<"from thread slot:" <<QThread::currentThreadId(); } }; #include "main.moc" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qDebug()<<"main thread:"<<QThread::currentThreadId(); QThread thread; Object obj; //通过信号连接派生类的槽函数,并通过信号触发槽函数。(槽函数在子线程中执行) Dummy dummy; obj.moveToThread(&thread); //将派生类对象移动到一个QThread中,该线程需要start。 QObject::connect(&dummy, SIGNAL(sig()), &obj, SLOT(slot())); // 通过信号连接派生类的槽函数,并通过信号触发槽函数。(槽函数在子线程中执行) . 这里的slot()函数,相当于run()函数的作用 thread.start(); dummy.emitsig(); return a.exec(); } ![在这里插入图片描述][20210414111606705.png] 总结: **从Qt4.4版本之后,因为QThread的run方法创建新线程这样实现与Qt设计的理念不符,Qt主推使用moveToThread方法来创建新线程。QThread 应该被看做是操作系统线程的接口或控制点,而不应该包含需要在新线程中运行的代码。需要运行的代码应该放到一个QObject的子类中,然后将该子类的对象moveToThread到新线程中** 具体的使用步骤如下: 1.从QObject派生一个类,将耗时的工作写在该类的槽函数中。 2.将派生类对象移动到一个QThread中,该线程需要start。(这一步使用moveToThread) 3.通过信号连接派生类的槽函数,并通过信号触发槽函数。(槽函数在子线程中执行) [参考][Link 6] [Qt QThread的moveToThread方法使用 === 例子还没有看][Qt QThread_moveToThread_ _] [推荐:例子写的很容易理解][Link 7] ## parent ## > **QObject `*`QObject::parent() const** 返回指向父对象的指针。 另请参阅setParent()和children()。 ## property ## > **QVariant QObject::property(const char `*`name) const** 返回对象的name属性的值。 如果不存在这样的属性,则返回的变量无效。 关于所有可用属性的信息是通过metaObject()和dynamicPropertyNames()提供的。 另请参阅setProperty(), QVariant::isValid(), metaObject()和dynamicPropertyNames()。 ## receivers ## > **\[protected\] > int QObject::receivers(const char `*`signal) const** 返回连接到该信号的接收器的数目。 由于插槽和信号都可以用作信号的接收器,并且可以多次建立相同的连接,因此接收器的数量与该信号建立的连接的数量是相同的。 当调用这个函数时,你可以使用SIGNAL()宏来传递一个特定的信号: if (receivers(SIGNAL(valueChanged(QByteArray))) > 0) { QByteArray data; get_the_value(&data); // expensive operation emit valueChanged(data); } 警告:这个函数违反了模块化的面向对象原则。然而,当您需要执行昂贵的初始化时,它可能会很有用,只有当某些东西连接到一个信号时。 参见isSignalConnected()。 ## removeEventFilter ## > **void QObject::removeEventFilter(QObject `*`obj)** 从此对象删除事件筛选器对象obj。如果没有安装这样的事件筛选器,请求将被忽略。 当此对象被销毁时,此对象的所有事件过滤器将自动删除。 删除事件过滤器总是安全的,即使在事件过滤器激活期间(即从eventFilter()函数)。 另请参阅installleventfilter()、eventFilter()和event()。 ## sender ## > **\[protected\] > QObject `*`QObject::sender() const** 如果在一个被信号激活的槽中调用,则返回一个指向发送信号的对象的指针;否则返回nullptr。该指针仅在从该对象的线程上下文调用该函数的插槽执行期间有效。 如果发送端被销毁,或者插槽与发送端信号断开连接,则该函数返回的指针将失效。 警告:这个函数违反了模块化的面向对象原则。然而,当许多信号连接到一个插槽时,访问发送方可能是有用的。 警告:如上所述,当通过Qt::DirectConnection从一个不同于该对象线程的线程调用slot时,此函数的返回值无效。此场景下请勿使用此功能。 参见senderSignalIndex()。 ## senderSignalIndex ## > **\[protected\] > int QObject::senderSignalIndex() const** 返回调用当前执行的slot的信号的元方法索引,它是由sender()返回的类的成员。如果在被信号激活的插槽外调用,则返回-1。 对于带有默认形参的信号,该函数将始终返回带有所有形参的索引,无论connect()使用的是哪个形参。例如,销毁的信号(QObject \*obj = \\nullptr)将有两个不同的索引(带和不带参数),但是这个函数将总是返回带参数的索引。当重载带有不同参数的信号时,这并不适用。 警告:这个函数违反了模块化的面向对象原则。然而,当许多信号连接到一个插槽时,访问信号索引可能是有用的。 这个函数的返回值是无效的,当通过Qt::DirectConnection从一个不同于该对象线程的线程调用slot时。此场景下请勿使用此功能。 另请参阅sender()、QMetaObject::indexOfSignal()和QMetaObject::method()。 ## setParent ## > **void QObject::setParent(QObject `*`parent)** 使对象成为parent的子对象。 另请参阅parent()和children()。 ## setProperty ## > **bool QObject::setProperty(const char`*`name, const QVariant &value)** 将对象的name属性的值设置为value。 如果使用Q\_PROPERTY在类中定义了属性,则成功时返回true,否则返回false。如果没有使用Q\_PROPERTY定义该属性,因此没有在元对象中列出,则将其作为动态属性添加,并返回false。 关于所有可用属性的信息是通过metaObject()和dynamicPropertyNames()提供的。 动态属性可以使用property()再次查询,也可以通过将属性值设置为无效的QVariant来删除。更改动态属性的值将导致向对象发送QDynamicPropertyChangeEvent。 注意:以“*q*”开头的动态属性保留给内部使用。 另请参阅property()、metaObject()、dynamicPropertyNames()和QMetaProperty::write()。 ## signalsBlocked ## > **bool QObject::signalsBlocked() const** 如果信号被阻塞,则返回true;否则返回false。 默认情况下信号不会被阻塞。 参见blockSignals()和QSignalBlocker。 ## startTimer ## > **int QObject :: startTimer(int interval, Qt :: TimerType timerType = Qt :: CoarseTimer)** 启动计时器并返回计时器标识符,如果无法启动,则返回0 会发生每一个计时器事件间隔毫秒直至`killTimer()`函数被调用。如果interval为0,则每次不再有窗口系统事件要处理时,计时器事件就会发生一次。 发生计时器事件时,将使用QTimerEvent事件参数类调用虚拟timerEvent()函数。重新实现此功能以获取计时器事件。 如果正在运行多个计时器,则可以使用`QTimerEvent :: timerId()`来找出激活了哪个计时器。 #include<QObject> #include<QDebug> class MyObject : public QObject { Q_OBJECT public: MyObject(QObject *parent = nullptr); protected: void timerEvent(QTimerEvent *event) override; }; MyObject::MyObject(QObject *parent) : QObject(parent) { startTimer(50); // 50-millisecond timer startTimer(1000); // 1-second timer startTimer(60000); // 1-minute timer using namespace std::chrono; startTimer(milliseconds(50)); startTimer(seconds(1)); startTimer(minutes(1)); // since C++14 we can use std::chrono::duration literals, e.g.: // startTimer(100ms); // startTimer(5s); // startTimer(2min); // startTimer(1h); } void MyObject::timerEvent(QTimerEvent *event) { qDebug() << "Timer ID:" << event->timerId(); } 注意,QTimer的准确性取决于底层操作系统和硬件。`timerType`参数允许您自定义计时器的准确性。关于不同定时器类型的信息,请参阅`Qt::TimerType`。大多数平台支持20毫秒的精度;一些提供更多。如果Qt无法交付请求的计时器事件数量,它将静默地丢弃一些。 `QTimer`类提供了一个高级编程接口,其中包含单次计时器和计时器信号,而不是事件。还有一个`QBasicTimer`类,它比QTimer更轻量级,也不像直接使用计时器id那样笨拙。 参见`timerEvent()`, `killTimer()`和`QTimer::singleShot()`。 > **\[since 5.9\] int QObject::startTimer(std::chrono::milliseconds time, Qt::TimerType timerType = Qt::CoarseTimer)** 这是一个重载函数。 启动计时器并返回计时器标识符,如果无法启动计时器则返回0。 在调用killTimer()之前,每次间隔都会发生一个计时器事件。如果time等于std::chrono::duration::zero(),那么当不再有需要处理的窗口系统事件时,计时器事件就会发生一次。 当计时器事件发生时,使用QTimerEvent事件参数类调用虚拟timerEvent()函数。重新实现这个函数以获取计时器事件。 如果有多个计时器正在运行,则可以使用QTimerEvent::timerId()来确定激活了哪个计时器。 例子: class MyObject : public QObject { Q_OBJECT public: MyObject(QObject *parent = nullptr); protected: void timerEvent(QTimerEvent *event) override; }; MyObject::MyObject(QObject *parent) : QObject(parent) { startTimer(50); // 50-millisecond timer startTimer(1000); // 1-second timer startTimer(60000); // 1-minute timer using namespace std::chrono; startTimer(milliseconds(50)); startTimer(seconds(1)); startTimer(minutes(1)); // since C++14 we can use std::chrono::duration literals, e.g.: startTimer(100ms); startTimer(5s); startTimer(2min); startTimer(1h); } void MyObject::timerEvent(QTimerEvent *event) { qDebug() << "Timer ID:" << event->timerId(); } 注意,QTimer的准确性取决于底层操作系统和硬件。timerType参数允许您自定义计时器的准确性。关于不同定时器类型的信息,请参阅Qt::TimerType。大多数平台支持20毫秒的精度;一些提供更多。如果Qt无法交付请求的计时器事件数量,它将静默地丢弃一些。 QTimer类提供了一个高级编程接口,其中包含单次计时器和计时器信号,而不是事件。还有一个QBasicTimer类,它比QTimer更轻量级,也不像直接使用计时器id那样笨拙。 这个函数是在Qt 5.9中引入的。 另请参见`timerEvent()`, `killTimer()`和`QTimer::singleShot()`。 ## thread ## > **QThread `*`QObject::thread() const** 返回对象所在的线程。 另请参见**moveToThread()**。 ## timerEvent ## > **\[virtual protected\]void QObject::timerEvent(QTimerEvent `*`event)** 可以在子类中重新实现此事件处理程序,以接收该对象的计时器事件。 QTimer为计时器功能提供了更高级别的接口,并且还提供了有关计时器的更多常规信息。计时器事件在event参数中传递。 另请参见`startTimer()`,`killTimer()`和`event()`。 ## tr ## **\[static\]QString QObject::tr(const char `*`sourceText, const char `*`disambiguation = nullptr, int n = -1)** 返回sourceText的翻译版本,对于包含复数的字符串,可以选择基于消歧字符串和值n;否则,如果没有合适的翻译字符串可用,则返回QString::fromUtf8(sourceText)。 例子: void MainWindow::createActions() { QMenu *fileMenu = menuBar()->addMenu(tr("&File")); ... 如果在同一上下文中的不同角色中使用了相同的sourceText,则可以在消歧中传递一个额外的标识字符串(默认为nullptr)。在Qt 4.4和更早的版本中,这是将注释传递给翻译器的首选方式。 例子: MyWindow::MyWindow() { QLabel *senderLabel = new QLabel(tr("Name:")); QLabel *recipientLabel = new QLabel(tr("Name:", "recipient")); ... 关于Qt翻译机制的一般详细描述,请参阅[编写翻译源代码][Link 4],关于消除歧义的信息,请参阅[消除歧义][Link 8]部分。 警告:只有在调用此方法之前安装了所有的翻译程序,此方法才可重入。不支持在执行翻译时安装或删除翻译程序。这样做可能会导致崩溃或其他不需要的行为。 参见QCoreApplication::translate()和[Qt的国际化][Qt 1]。 # 宏文档 # ## QT\_NO\_NARROWING\_CONVERSIONS\_IN\_CONNECT ## 当使用基于PMF的语法连接信号和槽时,定义此宏将禁用信号携带的参数和槽接受的参数之间的缩小和浮点到积分的转换。 此功能在Qt 5.8中引入。 也可以参考[QObject :: connect][QObject _ connect] ## Q\_CLASSINFO(Name, Value) ## 该宏将额外的信号与该类相管理,可以使用`QObject :: metaObject()`获得该信息。Qt仅在Qt D-Bus和Qt QML模块中有限地使用此功能。 额外信息采用名称字符串和值文字字符串的形式。 例子: class MyClass : public QObject { Q_OBJECT Q_CLASSINFO("Author", "Pierre Gendron") Q_CLASSINFO("URL", "http://www.my-organization.qc.ca") public: ... }; See also [QMetaObject::classInfo()][QMetaObject_classInfo], [Using Qt D-Bus Adaptors][], and [Extending QML][] ## Q\_DISABLE\_COPY(Class) ## 禁止对给定类使用复制构造函数和赋值运算符。 QObject的子类实例不应该被认为是可以复制或分配的值,而是唯一的标识。这意味着,当您创建自己的QObject子类(director或indirect)时,不应为其提供复制构造函数或赋值运算符。但是,仅从类中省略它们可能还不够,因为如果您错误地编写了一些需要复制构造函数或赋值运算符的代码(这很容易做到),则编译器会为您精心创建它。您必须做更多。 好奇的用户会看到,从QObject派生的Qt类通常在私有部分包含以下宏: class MyClass : public QObject { private: Q_DISABLE_COPY(MyClass) }; 它在private部分声明了一个复制构造函数和一个赋值运算符,因此如果您错误地使用它们,编译器将报告一个错误。 class MyClass : public QObject { private: MyClass(const MyClass &) = delete; MyClass &operator=(const MyClass &) = delete; }; 但是,即使这样也可能无法完全解决所有情况。您可能会想这样做: QWidget w = QWidget(); 首先,不要那样做。大多数编译器将生成使用复制构造函数的代码,因此将报告隐私侵犯错误,但不需要C++编译器以特定的方式生成该语句的代码。它既可以使用复制构造函数也不能使用我们私有的赋值操作符生成代码。在这种情况下,不会报告错误,但是当您调用w的成员函数时,应用程序可能会崩溃。 另请参见`Q_DISABLE_COPY_MOVE`和`Q_DISABLE_MOVE` ## Q\_DISABLE\_COPY\_MOVE(Class) ## 一个方便的宏,它结合使用Q\_DISABLE\_COPY和Q\_DISABLE\_MOVE,为给定的类禁用复制构造函数,赋值运算符,移动构造函数和移动赋值运算符。 此功能在Qt 5.13中引入。 另请参见`Q_DISABLE_COPY`和`Q_DISABLE_MOVE`。 ## Q\_DISABLE\_MOVE(Class) ## 禁止使用给定Class的move构造函数和move赋值运算符。 此功能在Qt 5.13中引入。 另请参见`Q_DISABLE_COPY`和`Q_DISABLE_COPY_MOVE`。 ## Q\_EMIT ## 如果要使用[第三方信号/插槽机制][Link 9]的Qt信号和插槽,请使用此宏替换用于发射信号的emit关键字。 当.pro文件中的CONFIG变量未指定`no_keywords`时,通常使用宏,但即使未指定\\u关键字,也可以使用宏。 The macro is normally used when no\_keywords is specified with the CONFIG variable in the .pro file, but it can be used even when no\_keywords is not specified. ## Q\_ENUM(…) ## 该宏在元对象系统中注册一个枚举类型。必须将其放在具有`Q_OBJECT`或`Q_GADGET`宏的类中的枚举声明之后。对于名称空间,请使用`Q_ENUM_NS()`。 例如: class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = nullptr); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; Q_ENUM(Priority) void setPriority(Priority priority); Priority priority() const; }; 用Q\_ENUM声明的枚举将其`QMetaEnum`注册在封闭的QMetaObject中。您还可以使用`QMetaEnum :: fromType()`获得QMetaEnum。 已注册的枚举也会自动注册到Qt元对象系统,从而使`QMetaType`知道它们,而无需用`Q_DECLARE_METATYPE()`。这将启用有用的功能:例如,如果在QVariant中使用,则可以将它们转换为字符串。同样,将它们传递给QDebug将打印出它们的名称。 请注意,枚举值按签名形式存储int在元对象系统中。使用超出有效值范围的值注册枚举int将导致通过元对象系统访问它们时发生溢出和潜在的未定义行为。例如,QML确实通过元对象系统访问注册的枚举。 此功能是在Qt 5.5中引入的。 另请参阅[属性系统][Link 10] ## Q\_ENUM\_NS(…) ## 该宏在元对象系统中注册一个枚举类型。必须将其放在具有`Q_NAMESPACE`宏的命名空间中的枚举声明之后。它与Q\_ENUM相同,但位于名称空间中。 用Q\_ENUM\_NS声明的枚举将其`QMetaEnum`注册在封闭的QMetaObject中。您还可以使用`QMetaEnum :: fromType()`获得QMetaEnum。 已注册的枚举也会自动注册到Qt元对象系统,从而使`QMetaType`知道它们,而无需用`Q_DECLARE_METATYPE()`。这将启用有用的功能:例如,如果在QVariant中使用,则可以将它们转换为字符串。同样,将它们传递给QDebug将打印出它们的名称。 请注意,枚举值按签名形式存储int在元对象系统中。使用超出有效值范围的值注册枚举int将导致通过元对象系统访问它们时发生溢出和潜在的未定义行为。例如,QML确实通过元对象系统访问注册的枚举。 此功能是在Qt 5.8中引入的。 另请参阅[属性系统][Link 10] ## Q\_FLAG(…) ## 该宏在元对象系统中注册单个[标志类型][Link 11]。它通常位于类定义中,以声明给定枚举的值可以用作标志并使用按位OR运算符进行组合。对于命名空间,请改用`Q_FLAG_NS()`。 该宏必须放在枚举声明之后,标志类型的声明是使用`Q_DECLARE_FLAGS()` 完成的 例如,在QItemSelectionModel中,通过以下方式声明SelectionFlags标志: class QItemSelectionModel : public QObject { Q_OBJECT public: ... enum SelectionFlag { NoUpdate = 0x0000, Clear = 0x0001, Select = 0x0002, Deselect = 0x0004, Toggle = 0x0008, Current = 0x0010, Rows = 0x0020, Columns = 0x0040, SelectCurrent = Select | Current, ToggleCurrent = Toggle | Current, ClearAndSelect = Clear | Select }; Q_DECLARE_FLAGS(SelectionFlags, SelectionFlag) Q_FLAG(SelectionFlags) ... } 注意: Q\_FLAG宏负责在元对象系统中注册各个标志值,因此除了此宏之外,没有必要使用Q\_ENUM()。 此功能是在Qt 5.5中引入的。 另请参阅[属性系统][Link 10] ## Q\_FLAG\_NS(…) ## 该宏在元对象系统中注册单个标志类型。它在具有`Q_NAMESPACE`宏的命名空间中使用,以声明给定枚举的值可以用作标志并使用按位OR运算符进行组合。它与Q\_FLAG相同,但位于名称空间中。 该宏必须放在枚举声明之后。 注意: Q\_FLAG\_NS宏负责在元对象系统中注册各个标志值,因此除了此宏之外,没有必要使用Q\_ENUM\_NS()。 此功能在Qt 5.8中引入。 另请参阅[属性系统][Link 10] ## Q\_GADGET ## Q\_GADGET是Q\_OBJECT宏的简化版本,用于不从QObject继承但仍要使用QMetaObject提供的某些反射功能的类。就像Q\_OBJECT宏一样,它必须出现在类的私有部分中。 Q\_GADGET可以具有Q\_ENUM,Q\_PROPERTY和Q\_INVOKABLE,但是它们不能具有信号或插槽。 Q\_GADGET使类成员staticMetaObject可用。staticMetaObject类型为QMetaObject,并提供对使用Q\_ENUMS声明的枚举的访问。 ## 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: ... }; 有关详细信息,请参见[Plug&Paint基本工具][Plug_Paint]示例。 另请参见`Q_DECLARE_INTERFACE()`,`Q_PLUGIN_METADATA()`和[如何创建Qt插件][Qt 2]。 ## Q\_INVOKABLE ## 将此宏应用于成员函数的声明,以允许它们通过元对象系统被调用。宏将在返回类型之前写入,如以下示例所示: class Window : public QWidget { Q_OBJECT public: Window(); void normalMethod(); Q_INVOKABLE void invokableMethod(); }; 该invokableMethod()函数使用Q\_INVOKABLE进行标记,从而使其在元对象系统中注册,并允许使用`QMetaObject::invokeMethod()`对其进行调用。由于normalMethod()未以这种方式注册功能,因此无法使用QMetaObject::invokeMethod()来调用它。 如果一个可调用的成员函数返回一个指向QObject或QObject的子类的指针,并且它是从QML中调用的,则应用特殊的所有权规则。更多信息请参阅[有关QML和C++的数据类型转换][QML_C]。 ## Q\_MOC\_INCLUDE ## Q\_MOC\_INCLUDE宏可以在类的内部或外部使用,并告诉[Meta Object Compiler][]添加一个include。 //将其放入您的代码中,生成的代码将包含此标头。 Q_MOC_INCLUDE (“ myheader.h”) 如果预先声明了用作属性或信号/插槽参数的类型,这将很有用。 此功能是在Qt 6.0中引入的。 ## Q\_NAMESPACE ## Q\_NAMESPACE宏可用于将QMetaObject功能添加到名称空间。 Q\_NAMESPACE可以具有Q\_CLASSINFO,Q\_ENUM\_NS,Q\_FLAG\_NS,但不能具有Q\_ENUM,Q\_FLAG,Q\_PROPERTY,Q\_INVOKABLE,信号或插槽。 Q\_NAMESPACE使外部变量staticMetaObject可用。staticMetaObject类型为QMetaObject,并提供对使用Q\_ENUM\_NS / Q\_FLAG\_NS声明的枚举的访问。 例如: namespace test { Q_NAMESPACE ... 此功能在Qt 5.8中引入。 另请参阅`Q_NAMESPACE_EXPORT`。 ## Q\_NAMESPACE\_EXPORT(EXPORT\_MACRO) ## Q\_NAMESPACE\_EXPORT宏可用于将QMetaObject功能添加到名称空间。 它的工作原理与Q\_NAMESPACE宏完全相同。但是,staticMetaObject使用提供的EXPORT\_MACRO限定符声明在名称空间中定义的外部变量。如果需要从动态库中导出对象,这将很有用。 例如: namespace test { Q_NAMESPACE_EXPORT(EXPORT_MACRO) ... 此功能在Qt 5.14中引入。 另请参见`Q_NAMESPACE`和[创建共享库][Link 12]。 ## Q\_OBJECT ## Q\_OBJECT宏必须出现在类定义的private部分,该类定义声明自己的信号和插槽,或者使用Qt的元对象系统提供的其他服务。 例如: #include <QObject> class Counter : public QObject { Q_OBJECT public: Counter() { m_value = 0; } int value() const { return m_value; } public slots: void setValue(int value); signals: void valueChanged(int newValue); private: int m_value; }; 注意:此宏要求该类是QObject的子类。使用Q\_GADGET而不是Q\_OBJECT来启用元对象系统对不是QObject子类的类中的枚举的支持。 ## Q\_PROPERTY(…) ## 此宏用于在继承QObject的类中声明属性。属性的行为类似于类数据成员,但它们具有可通过元对象系统访问的附加特性。 Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName [(READ getFunction | WRITE setFunction)]) [RESET resetFunction] [NOTIFY notifySignal] [REVISION int | REVISION(int[, int])] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [BINDABLE bindableProperty] [CONSTANT] [FINAL] [REQUIRED]) 属性名和类型以及READ函数是必需的。类型可以是QVariant支持的任何类型,也可以是用户定义的类型。其他项是可选的,但写函数是常见的。属性默认为true,但USER默认为false。 例如: Q_PROPERTY(QString title READ title WRITE setTitle USER true) 有关如何使用此宏的更多详细信息,以及其使用的更详细的示例,请参见有关Qt的[Property System][Link 10]的讨论。 ## Q\_REVISION ## 将此宏应用于成员函数的声明,以在元对象系统中用修订号标记它们。宏将在返回类型之前写入,如以下示例所示: class Window : public QWidget { Q_OBJECT Q_PROPERTY(int normalProperty READ normalProperty) Q_PROPERTY(int newProperty READ newProperty REVISION(2, 1)) public: Window(); int normalProperty(); int newProperty(); public slots: void normalMethod(); Q_REVISION(2, 1) void newMethod(); }; 当使用元对象系统将对象动态公开给另一个API时,这很有用,因为您可以匹配另一个API的多个版本所需的版本。考虑下面的简化示例: Window window; int expectedRevision = 0; const QMetaObject *windowMetaObject = window.metaObject(); for (int i=0; i < windowMetaObject->methodCount(); i++) if (windowMetaObject->method(i).revision() <= expectedRevision) exposeMethod(windowMetaObject->method(i)); for (int i=0; i < windowMetaObject->propertyCount(); i++) if (windowMetaObject->property(i).revision() <= expectedRevision) exposeProperty(windowMetaObject->property(i)); 使用与上一个示例相同的Window类,仅当预期版本2.1或更高版本时,newProperty和newMethod才会在此代码中公开。 由于所有方法0如果未加标签,都被认为是修订版,所以Q\_REVISION(0)或的标签Q\_REVISION(0, 0)无效并被忽略。 您可以将一个或两个整数参数传递给Q\_REVISION。如果传递一个参数,则仅表示次要版本。这意味着未指定主要版本。如果您传递两个,则第一个参数是主要版本,第二个参数是次要版本。 元对象系统本身不使用此标记。**当前,这仅由QtQml模块使用**。 有关更通用的字符串标签,请参见[QMetaMethod :: tag()][QMetaMethod _ tag] 另请参见[QMetaMethod :: revision()][QMetaMethod _ revision]。 # 成员函数 # [Qt]: https://blog.csdn.net/zhizhengguan/article/details/115521647 [installEventFilter]: https://doc.qt.io/qt-6/qobject.html#installEventFilter [eventFilter]: https://doc.qt.io/qt-6/qobject.html#eventFilter [QTimer]: https://doc.qt.io/qt-6/qtimer.html [Link 1]: https://doc.qt.io/qt-6/moc.html [Link 2]: https://doc.qt.io/qt-6/qt.html#ConnectionType-enum [Link 3]: https://doc.qt.io/qt-6/eventsandfilters.html#sending-events [UI]: https://blog.csdn.net/zhizhengguan/article/details/100353593 [tr]: https://doc.qt.io/qt-6/qobject.html#tr [Link 4]: https://doc.qt.io/qt-6/i18n-source-translation.html [Link 5]: https://doc.qt.io/qt-6/qtwidgets-tools-plugandpaint-app-example.html [Q_INVOKABLE]: https://doc.qt.io/qt-6/qobject.html#Q_INVOKABLE [QPointer]: https://doc.qt.io/qt-6/qpointer.html [20210414111606705.png]: /images/20221022/a9357b312a7d47af8fa6ee0417865ca4.png [Link 6]: https://baijiahao.baidu.com/s?id=1615219045511741840&wfr=spider&for=pc [Qt QThread_moveToThread_ _]: https://my.oschina.net/weiweiqiao/blog/4436701 [Link 7]: https://blog.csdn.net/t46414704152abc/article/details/52133377 [Link 8]: https://doc.qt.io/qt-6/i18n-source-translation.html#disambiguation [Qt 1]: https://doc.qt.io/qt-6/internationalization.html [QObject _ connect]: https://doc.qt.io/qt-6/qobject.html#connect [QMetaObject_classInfo]: https://doc.qt.io/qt-6/qmetaobject.html#classInfo [Using Qt D-Bus Adaptors]: https://doc.qt.io/qt-6/usingadaptors.html [Extending QML]: https://doc.qt.io/qt-6/qtquick-codesamples.html#extending-qml [Link 9]: https://doc.qt.io/qt-6/signalsandslots.html#3rd-party-signals-and-slots [Link 10]: https://blog.csdn.net/zhizhengguan/article/details/115523631 [Link 11]: https://doc.qt.io/qt-6/qflags.html [Plug_Paint]: https://doc.qt.io/qt-6/qtwidgets-tools-plugandpaint-plugins-basictools-example.html [Qt 2]: https://doc.qt.io/qt-6/plugins-howto.html [QML_C]: https://doc.qt.io/qt-6/qtqml-cppintegration-data.html [Meta Object Compiler]: https://blog.csdn.net/zhizhengguan/article/details/115532314 [Link 12]: https://doc.qt.io/qt-6/sharedlibrary.html [QMetaMethod _ tag]: https://doc.qt.io/qt-6/qmetamethod.html#tag [QMetaMethod _ revision]: https://doc.qt.io/qt-6/qmetamethod.html#revision
还没有评论,来说两句吧...