#(14):對話框數據傳遞
對話框的出現用于完成一個簡單的或者是短期的任務。對話框與主窗口之間的數據交互相當重要。本節將講解如何在對話框和主窗口之間進行數據交互。按照前文的講解,對話框分為模態和非模態兩種。我們也將以這兩種為例,分別進行闡述。
模態對話框使用了`exec()`函數將其顯示出來。`exec()`函數的真正含義是開啟一個新的事件循環(我們會在后面的章節中詳細介紹有關事件的概念)。所謂事件循環,可以理解成一個無限循環。Qt 在開啟了事件循環之后,系統發出的各種事件才能夠被程序監聽到。這個事件循環相當于一種輪詢的作用。既然是無限循環,當然在開啟了事件循環的地方,代碼就會被阻塞,后面的語句也就不會被執行到。因此,對于使用了`exec()`顯示的模態對話框,我們可以在`exec()`函數之后直接從對話框的對象獲取到數據值。
看一下下面的代碼:
~~~
void MainWindow::open()
{
QDialog dialog(this);
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.exec();
qDebug() << dialog.result();
}
~~~
上面的代碼中,我們使用`exec()`顯示一個模態對話框。最后一行代碼,`qDebug()`類似于`std::cout`或者 Java 的`System.out.println();`語句,將后面的信息輸出到標準輸出,一般就是控制臺。使用`qDebug()`需要引入頭文件。在`exec()`函數之后,我們直接可以獲取到 dialog 的數據值。注意,`exec()`開始了一個事件循環,代碼被阻塞到這里。由于`exec()`函數沒有返回,因此下面的`result()`函數也就不會被執行。直到對話框關閉,`exec()`函數返回,此時,我們就可以取得對話框的數據。
需要注意的一點是,如果我們設置 dialog 的屬性為`WA_DeleteOnClose`,那么當對話框關閉時,對象被銷毀,我們就不能使用這種辦法獲取數據了。在這種情況下,我們可以考慮使用 parent 指針的方式構建對話框,避免設置`WA_DeleteOnClose`屬性;或者是利用另外的方式。
實際上,`QDialog::exec()`是有返回值的,其返回值是`QDialog::Accepted`或者`QDialog::Rejected`。一般我們會使用類似下面的代碼:
~~~
QDialog dialog(this);
if (dialog.exec() == QDialog::Accepted) {
// do something
} else {
// do something else
}
~~~
來判斷對話框的返回值,也就是用戶是點擊了“確定”還是“取消”。更多細節請參考`QDialog`文檔。
模態對話框相對簡單,如果是非模態對話框,`QDialog::show()`函數會立即返回,如果我們也這么寫,就不可能取得用戶輸入的數據。因為`show()`函數不會阻塞主線程,`show()`立即返回,用戶還沒有來得及輸入,就要執行后面的代碼,當然是不會有正確結果的。那么我們就應該換一種思路獲取數據,那就是使用信號槽機制。
由于非模態對話框在關閉時可以調用`QDialog::accept()`或者`QDialog::reject()`或者更通用的`QDialog::done()`函數,所以我們可以在這里發出信號。另外,如果找不到合適的信號發出點,我們可以重寫`QDialog::closeEvent()`函數,在這里發出信號。在需要接收數據的窗口(這里是主窗口)連接到這個信號即可。類似的代碼片段如下所示:
~~~
//!!! Qt 5
// in dialog:
void UserAgeDialog::accept()
{
emit userAgeChanged(newAge); // newAge is an int
QDialog::accept();
}
// in main window:
void MainWindow::showUserAgeDialog()
{
UserAgeDialog *dialog = new UserAgeDialog(this);
connect(dialog, &UserAgeDialog::userAgeChanged, this, &MainWindow::setUserAge);
dialog->show();
}
// ...
void MainWindow::setUserAge(int age)
{
userAge = age;
}
~~~
上面的代碼很簡單,這里不再贅述。另外,上述代碼的 Qt 4 版本也應該可以很容易地實現。
不要擔心如果對話框關閉,是不是還能獲取到數據。因為 Qt 信號槽的機制保證,在槽函數在調用的時候,我們始終可以使用`sender()`函數獲取到 signal 的發出者。關于`sender()`函數,可以在文檔中找到更多的介紹。順便說一句,`sender()`函數的存在使我們可以利用這個函數,來實現一個只能打開一個的非模態對話框(方法就是在對話框打開時在一個對話框映射表中記錄下標記,在對話框關閉時利用`sender()`函數判斷是不是該對話框,然后從映射表中將其刪除)。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)