【Qt】QObject详解
00. 目錄
文章目錄
- 00. 目錄
- 01. 概述
- 02. 線程親和性
- 03. 沒有拷貝構造函數或賦值運算符
- 04. 自動連接
- 05. 動態屬性
- 06. 國際化
- 07. 屬性文檔
- 08. 常用成員方法
- 09. 附錄
01. 概述
QObject類是所以Qt類的基類,也是Qt對象模型的核心。這個模型中的核心特性就是能讓對象鍵無縫通信的信號和槽的機制。我們可以使用connect()函數將一個信號連接到一個槽上,也可以使用disconnect()刪除這個連接。為了防止無休止的的信號通知,還可以使用blockSignals()來臨時阻塞信號。而connectNotify()和disconnectNotify()兩個函數可以讓我們能夠跟蹤一個對象上信號的連接變化。
QObject對象使用對象樹的方式來組織它們自己。所以,當你以另一個對象作為父來創建一個QObject對象時,該對象會自動的將它自己添加的父級的孩子列表中,父級會接管該對象的所有權,也就是說,父級會在自己的析構函數中自動釋放它的所有孩子。我們可以使用對象名通過findChild()或findChildren()函數在對象樹中查找一個或多個對象。
每一個QObject對象都有一個objectName(),并且它的類名也可以使用metaObject()對象來獲取。還可以使用inherits()來判斷一個對象所屬的類是否繼承自另一個類。
當一個對象被銷毀時,它會發出destroyed()信號。我們可以捕捉該信號來做一些最后的處理。
QObject對象可以使用event()函數來處理事件,還可以通過installEventFilter()和eventFilter()函數來過濾或攔截其他對象的事件。QObject還支持基本的定時器。
注意,對于所有實現信號、槽、或者屬性的QObject對象來說**,Q_OBJECT宏**都是必須的。我們推薦在每一個QObject的子類中使用這個宏,無論其是否實現信號、槽或屬性,這可以避免一些奇怪的行為。
Qt中,所有的控件都派生自QObject。而QObject中的isWidgetType()函數可以判斷一個對象是否是一個控件。
QObject所有的成員方法:
02. 線程親和性
QObject對象有一個線程親和性,或者是它生存在某個特定的線程中。當一個QObject對象接收到一個queued signal或一個posted event時,相應的槽函數或事件處理器會在該對象所生存的線程中執行。
注意,如果一個線程沒有線程親和性,或者,如果它生存的線程沒有運行事件循環,那么它不能接收到queued singal或posted event。
默認情況下,QObject對象生存在創建它的那個線程中。但我們可以使用thread()函數來查詢對象的線程親和性,還可以使用moveToThread()函數來改變一個對象的線程親和性。并且,所有的對象都和它的父生存在同一個線程中。因此:
- 在調用setParent()時,如果涉及到的兩個對象不在同一個線程,就會失敗。
- 當一個QObject對象被移動到其他線程時,它們所有孩子也會自動被移動。
- moveToThread()在對象有父級的時候,會失敗
- 如果一個QObject對象是在QThread::run()中被創建的,那么它們不能成為QThread對象的孩子,因為QThread對象并不生存在調用QThread::run()的那個線程中。
注意,一個QObject對象的成員變量不會自動成為該對象的孩子。對象間的父子關系必須通過向子對象的構造函數傳遞一個指針,或通過調用setParent()來實現。如果沒有這樣做,那么,當調用moveToThread()時,QObject對象的成員變量會仍然存在于老線程中。
03. 沒有拷貝構造函數或賦值運算符
QObject對象既 沒有拷貝構造函數也沒有賦值運算符。實際上,它們在QObject類中都進行了聲明,只不過是放在了private區域,并使用了Q_DISABLE_COPY()宏進行了禁用。這樣一來,你應該在需要QObject子類作為值的地方,使用一個QObject指針來代替。例如,因為沒有拷貝構造函數,你不能將QObject對象作為值存儲到容器類中, 必須使用指針來存儲。
04. 自動連接
Qt的元對象系統提供了一個自動連接信號和槽的機制。只要對象定義了合適的對象名,并且相應的槽函數的聲明遵循移動的命名約定,那么就會在運行時通過QMetaObject::connectSlotsByName()函數來自動進行信號和槽的連接。我們在之前的例子中,經常使用的“轉到槽…”操作,就通過這種機制實現的。
05. 動態屬性
從Qt4.2開始,就可以在運行時動態的從QObject對象上添加或移除屬性。動態屬性不需要在編譯時進行聲明,但它們提供了和靜態屬性一樣的效率,并使用同一套API進行操作,即使用property()函數來讀取屬性值,使用setProperty()函數來修改屬性值。
而從Qt4.3開始,Qt Designer也支持了動態屬性,并且Qt的標準控件和用戶自定義的控件都可以被賦予動態屬性。
06. 國際化
所有QObject的子類都支持Qt的翻譯特性,也使我們可以把應用程序的用戶界面翻譯成不同的語言。而為了使用戶可見的文本可以被翻譯,我們必須使用tr()函數來將這些文本包圍起來。
07. 屬性文檔
屬性只有一個:objectName,類型是QString
相關成員方法
QString objectName() constvoid setObjectName(const QString &name)08. 常用成員方法
QObject::QObject(QObject *parent = nullptr):構造函數 有一點注意,當控件的父對象為空時,這個控件就是一個頂層窗口控件。QObject::~QObject():析構函數 當對象銷毀時,所有和它相關的信號都回斷開,相關的事件也會從事件隊列中移除。建議使用deleteLater()來銷毀對象,它比直接銷毀delete更安全。 手冊中有一個警告:刪除所有子對象。如果這些對象中的任何一個在棧或全局上,則程序遲早會崩潰。 我的理解是:使用new在堆上分配空間來創建子對象,讓父對象負責它的內存回收;如果要在棧上創建對象,就不要指定它的父對象,以免父對象回收了棧內存,導致崩潰。 不建議從父項外部保留指向子對象的指針。如果仍然這樣做,則destroy()信號檢測對象何時被銷毀。警告:等待傳遞掛起事件時刪除QObject可能會導致崩潰。如果QObject存在于與當前正在執行的不同的線程中,則不能直接刪除它。改為使用deleteLater(),這將導致事件循環在所有掛起事件傳遞給它之后刪除該對象。 bool QObject::blockSignals(bool block) 當參數block=true時,該對象的信號被阻塞,即信號發不出去;除了destroy()信號。 const QObjectList&QObject :: children()const 返回子對象列表,QObjectList的定義:typedef QList < QObject * > QObjectList ; 列表第一個子項是最初添加的,最后一個子項是最后添加的; 在QWidget中的子項會因為提升函數raised()和降低lowered(),導致子項在列表中的變化,提升后子項將成為列表的最后一個,降低后會成為列表中最后一個。connect函數組 QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection);QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, Qt::ConnectionType type = Qt::AutoConnection);QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const char *method, Qt::ConnectionType type = Qt::AutoConnection) const;QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection);QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor);QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, const QObject *context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)disconnect void QObject :: dumpObjectInfo() const 將有關此對象的信號連接等的信息轉儲到調試輸出。QList QObject::dynamicPropertyNames() const 返回使用setProperty()加載的屬性列表。bool QObject::event(QEvent *e) [virtual] 此虛函數接收事件到對象,如果事件e被識別和處理,則應返回true 。可以重新實現event()函數以自定義對象的行為。 確保為所有未處理的事件調用父事件類實現。bool QObject::eventFilter(QObject *watched, QEvent *event) [virtual] 如果此對象執行installEventFilter安裝為watched對象的事件過濾器,則過濾事件。 在重新實現此函數時,如果要過濾掉事件,即停止進一步處理,則返回true; 否則返回false。 警告:如果在此函數中刪除接收器對象,請確保返回true。否則,Qt會將事件轉發給已刪除的對象,程序可能會崩潰。T QObject::findChild(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const 返回找到第一個子項或孫子項; options取值: Qt::FindDirectChildrenOnly:只在子項中查找; Qt::FindChildrenRecursively:在所有項(包括孫子、重孫子等)中遞歸查找如:返回parentWidget中名字為button1的QPushButton QPushButton *button = parentWidget->findChild<QPushButton *>("button1");QList QObject::findChildren(const QString &name = QString(), Qt::FindChildOptions options = Qt::FindChildrenRecursively) const 返回可以強制轉換為T類型的給定name 的該對象的所有子項,如果沒有找到,則返回空列表。 如:返回parentWidget中所有QPushButton子項: QList<QPushButton *> allPButtons = parentWidget.findChildren<QPushButton *>(); QList QObject::findChildren(const QRegularExpression &re, Qt::FindChildOptions options = Qt::FindChildrenRecursively) const 上個函數的重載,可以使用正則表達來搜索子項。bool QObject::inherits(const char *className) const 判斷一個類是不是繼承子className QTimer *timer = new QTimer; // QTimer 繼承自 QObject timer->inherits("QTimer"); // 返回 true timer->inherits("QObject"); // 返回 true timer->inherits("QAbstractButton"); // 返回 false void QObject::installEventFilter(QObject *filterObj) 在此該類上安裝事件過濾器,即filterObj監視該類的事件發生。bool QObject::isWidgetType() const 如果該類繼承自QWidget,則返回true,該函數比inherits(“QWidget”)快bool QObject::isWindowType() const 如果該類繼承自QWindow,則返回true,該函數比inherits(“QWindow”)快void QObject::killTimer(int id) 使用計時器標識id來終止計時器;該標識id是int QObject::startTimer返回的。const QMetaObject *QObject::metaObject() const 返回指向該對象的元對象的指針。 元對象包含有關繼承QObject的類的信息,例如類名,超類名,屬性,信號和槽。包含Q_OBJECT宏的每個QObject子類都具有一個元對象。 實例代碼如下,如果類沒有實例化過,可以使用staticMetaObject來獲取元對象信息: QObject *obj = new QPushButton; obj->metaObject()->className(); // returns "QPushButton"QPushButton::staticMetaObject.className(); // returns "QPushButton"void QObject::moveToThread(QThread *targetThread) 更改此對象及其子對象的線程關聯。如果對象具有父對象,則無法移動該對象。事件處理將在targetThread中繼續。QString objectName() const 和 void setObjectName(const QString &name) 設置對象名,默認是空;該名字在findChild和findChildren,即查找子項中使用。QObject *QObject::parent() const 和 void QObject::setParent(QObject *parent) 獲取和設置父對象指針。QVariant QObject::property(const char *name) const 返回名字為name的屬性值;bool QObject::setProperty(const char *name, const QVariant &value) 設置名字為name的屬性值value;bool QObject::signalsBlocked() const 阻止該對象發送信號,可以暫停發送信號,默認不阻止;int QObject::startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer) 啟動計時器并返回計時器標識符,如果無法啟動計時器,則返回零。 啟動后,每次超時將會觸發 timerEvent(QTimerEvent *event) 事件。 可以使用killTimer來終止計時。 當有多個計時器是,可以通過QTimerEvent::timerId() 獲取計時器標識符來區別。 官方示例 class MyObject : public QObject {Q_OBJECTpublic:MyObject(QObject *parent = 0);protected:void timerEvent(QTimerEvent *event) override; };MyObject::MyObject(QObject *parent): QObject(parent) {startTimer(50); // 50-millisecond timerstartTimer(1000); // 1-second timerstartTimer(60000); // 1-minute timerusing 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(); }QThread *QObject::thread() const 返回對象所在的線程。公有槽函數
void QObject::deleteLater() 安全的刪除對象,可以調用多次。信號
void QObject::destroyed(QObject *obj = nullptr) [signal] 該信號在對象obj被銷毀之前立即發出,并且不能signalsBlocked函數阻擋。 發出此信號后,所有對象的子項都會立即被銷毀。void QObject::objectNameChanged(const QString &objectName) 在更改對象名稱后發出此信號。新對象名稱作為objectName傳遞。 注意:這是一個private信號。它可以用于信號連接,但不能由用戶發出。受保護成員方法
大部分時虛函數,可以由用戶來實現void QObject :: childEvent(QChildEvent * event)[virtual protected] 可以重新實現子項事件處理,包括添加子項事件、刪除子項事件void QObject::connectNotify(const QMetaMethod &signal) [virtual protected] 當連接信號時,觸發該函數;void QObject::disconnectNotify(const QMetaMethod &signal) [virtual protected] 當斷開信號時,觸發該函數;void QObject::customEvent(QEvent *event) 自定義事件bool QObject::isSignalConnected(const QMetaMethod &signal) const 如果signal信號已經連接,則返回trueint QObject::receivers(const char *signal) const 返回連接到signal的接收者的數量。QObject * QObject::sender() const 返回發送者指針; 當與發送者不在同一個線程中,并使用Qt::DirectConnection時,此函數無效。int QObject::senderSignalIndex() const 發送信號索引void QObject::timerEvent(QTimerEvent *event) 計時器事件宏定義
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT Q_CLASSINFO(Name, Value) 此宏將額外信息與類關聯,該類可使用QObject::metaObject()獲得。僅在Active Qt,Qt D-Bus和Qt QML中使用Q_DISABLE_COPY(Class) 禁用給定Class的復制構造函數和賦值運算符。Q_EMIT 如果要將Qt信號和插槽與第三方信號/插槽機制一起使用,請使用此宏替換發射信號的關鍵字。Q_ENUM( …) 使用元對象系統注冊枚舉類型Q_ENUM_NS( …) 此宏使用元對象系統注冊枚舉類型。它必須放在具有Q_NAMESPACE宏的命名空間中的枚舉聲明之后。它與Q_ENUM相同,但在命名空間中。 Q_FLAG( …) Q_FLAG_NS( …) Q_GADGET Q_INTERFACES( …) Q_INVOKABLE Q_NAMESPACE Q_OBJECT Q_PROPERTY( …) Q_REVISION Q_SET_OBJECT_NAME(Object) Q_SIGNAL Q_SIGNALS Q_SLOT Q_SLOTS09. 附錄
9.1 Qt教程匯總
網址:https://dengjin.blog.csdn.net/article/details/115174639
9.2 參考博客
網址:https://blog.csdn.net/Amnes1a/article/details/69371711
總結
以上是生活随笔為你收集整理的【Qt】QObject详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Qt】Qt窗口几何布局
- 下一篇: 【Qt】QWidget类详解(函数篇)