Qt5基本模塊
Qt Creator 中的快捷鍵
? 注釋:ctrl + /
? 運?:ctrl + R
? 編譯:ctrl + B
? 字體縮放:ctrl + 鼠標滑輪
? 查找:ctrl + F
? 整行移動:ctrl + shift + ?/?
? 幫助?檔:F1
? 自動對齊:ctrl + i;
? 同名之間的 .h 和 .cpp 的切換:F4
? 生成函數聲明的對應定義: alt + enter
認識對象模型(對象樹)
在 Qt 中,對象樹是一種非常重要的概念,用于管理和組織對象之間的關系。以下是對 Qt 對象樹的詳細理解介紹:
1. 對象樹的基本概念
- 定義:Qt 的對象樹是一種層次化的對象管理機制,基于
QObject
類實現。每個QObject
對象可以有一個父對象(parent
),并且可以擁有多個子對象(children
)。 - 父子關系:當創建一個
QObject
對象時,可以通過構造函數指定一個父對象。如果指定了父對象,那么這個新創建的對象會自動成為父對象的子對象,并被添加到父對象的children()
列表中。
2. 對象樹的作用
-
生命周期管理:父對象負責管理其子對象的生命周期。當父對象被銷毀時,其所有子對象也會被自動銷毀。這種機制避免了內存泄漏,同時也簡化了對象的管理。
-
事件傳播:在 GUI 程序中,事件(如鼠標點擊、鍵盤輸入等)會從父對象向下傳播到子對象。這種機制使得事件處理更加高效和靈活。
-
組件化管理:對象樹使得 GUI 組件的組織更加清晰。例如,一個窗口(
QWidget
)可以包含多個按鈕、文本框等子組件。當窗口被銷毀時,所有子組件也會被自動銷毀。
3. 對象樹的實現機制
- 構造函數中的父對象參數:
QObject
的構造函數接受一個QObject*
類型的參數,表示父對象。例如:
在這個例子中,QObject* parent = new QObject(); QObject* child = new QObject(parent);
child
的父對象是parent
,child
會被自動添加到parent
的children()
列表中。 children()
方法:每個QObject
對象都有一個children()
方法,返回一個包含所有子對象的列表。- 自動銷毀機制:當父對象被銷毀時,Qt 會自動調用子對象的析構函數,銷毀所有子對象。
4. 對象樹的使用場景
- GUI 組件管理:在 Qt 的 GUI 程序中,
QWidget
是所有可視組件的基類,它繼承自QObject
。例如:
在這個例子中,QWidget* window = new QWidget(); QPushButton* button = new QPushButton(window);
button
是window
的子組件。當window
被銷毀時,button
也會被自動銷毀。 - 資源管理:對象樹機制不僅適用于 GUI 組件,還可以用于管理其他資源,如文件句柄、網絡連接等。
5. 注意事項
- 避免循環引用:在使用對象樹時,要避免創建循環引用(即對象 A 是對象 B 的父對象,同時對象 B 也是對象 A 的父對象)。這會導致對象無法正確銷毀,從而引發內存泄漏。
- 手動管理子對象:雖然對象樹會自動管理子對象的生命周期,但也可以手動刪除子對象。例如:
在這種情況下,子對象會從父對象的QObject* child = new QObject(parent); delete child; // 手動刪除子對象
children()
列表中自動移除。
Qt 的對象樹是一種強大的機制,用于管理和組織對象之間的關系。它不僅簡化了內存管理,還使得 GUI 組件的組織更加清晰。通過合理使用對象樹,可以提高代碼的可維護性和可擴展性。
在 Qt 中,盡量在構造的時候就指定parent對象,并且?膽在堆上創建。
## 信號與槽
如果要使用信號與槽(signal 和 slot)的機制就必須加入Q_OBJECT宏;這個宏不僅用于支持信號與槽機制,還允許 Qt 的元對象系統(Meta-Object System)自動生成一些輔助代碼。
信號的本質就是事件。
- 如:按鈕單擊、雙擊 ,窗?刷新等。
- 信號的呈現形式就是函數
- 信號函數只需要聲明,不需要定義(實現)。
- 信號函數聲明用 signals 關鍵字修飾
槽(Slot)就是對信號響應的函數。
- 槽是普通的成員函數,用于處理信號。槽函數可以手動實現,也可以通過 Qt 的機制自動生成。
- 可以定義在類的任何位置( public、protected 或 private)。
- 可以具有任何參數,可以被重載,也可以被直接調
用(但是不能有默認參數 - 槽函數需要定義(實現)。
- 槽函數可以與?個信號關聯,當信號被發射時,關聯的槽函數被自動執行。
- 槽函數用 public slots、protected lots 或者 private slots 修飾。
signals 和 slots 是 Qt 在 C++ 的基礎上擴展的關鍵字
connect函數
在 Qt 中,QObject 類提供了?個靜態成員函數connect(),該函數專門來關聯指定的信號函數和槽函數。
connect函數原型
connect (const QObject *sender,
const char * signal ,
const QObject * receiver ,
const char * method ,
Qt::ConnectionType type = Qt::AutoConnection )
參數說明:
? sender:信號的發送者;
? signal:發送的信號(信號函數);
? receiver:信號的接收者;
? method:接收信號的槽函數;
? type:用于指定關聯方式,默認的關方式為 Qt::AutoConnection,通常不需要手動設定。
自動生成槽函數的機制
- 步驟:
- 在 Qt Creator 中,添加一個信號(
mySignal(int value)
) - 右鍵點擊信號或信號聲明。
- 選擇 “轉到槽”(Go to Slot)或 “轉到信號”(Go to Signal)。
- Qt Creator 會自動生成一個槽函數的聲明和定義,并將其添加到類中。
- 在 Qt Creator 中,添加一個信號(
例如,對于信號 mySignal(int value)
,Qt Creator 會生成如下代碼:
// 在頭文件中自動生成槽函數聲明
public slots:void on_mySignal(int value);// 在實現文件中自動生成槽函數定義
void MyObject::on_mySignal(int value)
{// 在這里實現槽函數的邏輯
}
- 自動生成的槽函數:
- 當你在類中聲明信號時,Qt 的元對象系統會自動為這些信號生成默認的槽函數。這些槽函數通常以
on_<SignalName>
的形式命名。 - 按照這種命名風格格定義的槽函數,會被 Qt ?動的和對應的信號進行連接。
日常寫代碼,最好還是不要依賴命名規則,而是顯式
使用 connect 更好。1. connect 可以更清晰直觀的描述信號和槽的連接關系。2. 防止信號或者槽的名字拼寫錯誤導致連接失效.
- 當你在類中聲明信號時,Qt 的元對象系統會自動為這些信號生成默認的槽函數。這些槽函數通常以
- 使用方法:
- 在類的聲明中,添加信號聲明。
- 在類的實現中,實現自動生成的槽函數。
- 使用
QObject::connect()
將信號連接到自動生成的槽函數。
通過 Qt 的 Q_INVOKABLE
宏
Q_INVOKABLE
宏可以將普通成員函數標記為可調用的槽函數。雖然這不是嚴格意義上的“自動生成”,但它允許開發者將任意函數作為槽函數使用。
- 使用方法:
- 在類的聲明中,使用
Q_INVOKABLE
宏標記成員函數。 - 這些函數可以直接作為槽函數使用。
- 在類的聲明中,使用
例如:
class MyObject : public QObject
{Q_OBJECT
public:MyObject(QObject* parent = nullptr);Q_INVOKABLE void mySlotFunction(int value); // 使用 Q_INVOKABLE 標記signals:void mySignal(int value);
};void MyObject::mySlotFunction(int value)
{qDebug() << "Slot function called with value:" << value;
}// 連接信號和槽
connect(this, &MyObject::mySignal, this, &MyObject::mySlotFunction);
自定義信號函數和槽函數
- ?定義信號函數書寫規范
(1)?定義信號函數必須寫到 “signals” 下;
(2)返回值為 void,只需要聲明,不需要實現;
(3)可以有參數,也可以發生重載 - ?定義槽函數書寫規范
(1)早期的 Qt 版本要求槽函數必須寫到 “public slots” 下,但是現在?級版本的 Qt 允許寫到類的 “public” 作用域中或者全局下;
(2)返回值為 void,需要聲明,也需要實現;
(3)可以有參數,可以發生重載;
3、發送信號
使用 “emit” 關鍵字發送信號。“emit” 是?個空的宏。"emit"其實是可選的,沒有什么含義,只
是為了提醒開發?員。
關聯函數一定要寫在發射信號之前
原因是,?先關聯信號和槽,?旦檢測到信號發射之后就會立即執行關聯的槽函數。反之,若先發射信號,此時還沒有關聯槽函數,當信號發射之后槽函數不會響應。
信號與槽的斷開
當"connect"函數第三個參數為"this" 時,第四個參數使? Lambda表達式時,可以省略掉 “this”;