QT基礎教程之五對話框QDialog
基本概念
對話框是 GUI 程序中不可或缺的組成部分。很多不能或者不適合放入主窗口的功能組件都必須放在對話框中設置。對話框通常會是一個頂層窗口,出現(xiàn)在程序最上層,用于實現(xiàn)短期任務或者簡潔的用戶交互。
Qt 中使用QDialog類實現(xiàn)對話框。就像主窗口一樣,我們通常會設計一個類繼承QDialog。QDialog(及其子類,以及所有Qt::Dialog類型的類)的對于其 parent 指針都有額外的解釋:如果 parent 為 NULL,則該對話框會作為一個頂層窗口,否則則作為其父組件的子對話框(此時,其默認出現(xiàn)的位置是 parent 的中心)。頂層窗口與非頂層窗口的區(qū)別在于,頂層窗口在任務欄會有自己的位置,而非頂層窗口則會共享其父組件的位置。
對話框分為模態(tài)對話框和非模態(tài)對話框。
模態(tài)對話框,就是會阻塞同一應用程序中其它窗口的輸入。
模態(tài)對話框很常見,比如“打開文件”功能。你可以嘗試一下記事本的打開文件,當打開文件對話框出現(xiàn)時,我們是不能對除此對話框之外的窗口部分進行操作的。
與此相反的是非模態(tài)對話框,例如查找對話框,我們可以在顯示著查找對話框的同時,繼續(xù)對記事本的內(nèi)容進行編輯。
標準對話框
所謂標準對話框,是 Qt 內(nèi)置的一系列對話框,用于簡化開發(fā)。事實上,有很多對話框都是通用的,比如打開文件、設置顏色、打印設置等。這些對話框在所有程序中幾乎相同,因此沒有必要在每一個程序中都自己實現(xiàn)這么一個對話框。
Qt 的內(nèi)置對話框大致分為以下幾類:
-
QColorDialog: 選擇顏色;
-
QFileDialog: 選擇文件或者目錄;
-
QFontDialog: 選擇字體;
-
QInputDialog: 允許用戶輸入一個值,并將其值返回;
-
QMessageBox: 模態(tài)對話框,用于顯示信息、詢問問題等;
-
QPageSetupDialog: 為打印機提供紙張相關的選項;
-
QPrintDialog: 打印機配置;
-
QPrintPreviewDialog:打印預覽;
-
QProgressDialog: 顯示操作過程。
自定義消息框
Qt 支持模態(tài)對話框和非模態(tài)對話框。
模態(tài)與非模態(tài)的實現(xiàn):
-
使用QDialog::exec()實現(xiàn)應用程序級別的模態(tài)對話框
-
使用QDialog::open()實現(xiàn)窗口級別的模態(tài)對話框
-
使用QDialog::show()實現(xiàn)非模態(tài)對話框。
模態(tài)對話框
- Qt 有兩種級別的模態(tài)對話框:
應用程序級別的模態(tài)
當該種模態(tài)的對話框出現(xiàn)時,用戶必須首先對對話框進行交互,直到關閉對話框,然后才能訪問程序中其他的窗口。
窗口級別的模態(tài)
該模態(tài)僅僅阻塞與對話框關聯(lián)的窗口,但是依然允許用戶與程序中其它窗口交互。窗口級別的模態(tài)尤其適用于多窗口模式。
一般默認是應用程序級別的模態(tài)。
在下面的示例中,我們調(diào)用了exec()將對話框顯示出來,因此這就是一個模態(tài)對話框。當對話框出現(xiàn)時,我們不能與主窗口進行任何交互,直到我們關閉了該對話框。
QDialog dialog;
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.exec();
非模態(tài)對話框
下面我們試著將exec()修改為show(),看看非模態(tài)對話框:
QDialog dialog(this);
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.show();
是不是事與愿違?對話框竟然一閃而過!這是因為,**show()函數(shù)不會阻塞當前線程,對話框會顯示出來,然后函數(shù)立即返回,代碼繼續(xù)執(zhí)行。**注意,dialog 是建立在棧上的,show()函數(shù)返回,MainWindow::open()函數(shù)結(jié)束,dialog 超出作用域被析構,因此對話框消失了。知道了原因就好改了,我們將 dialog 改成堆上建立,當然就沒有這個問題了:
QDialog *dialog = new QDialog;
dialog->setWindowTitle(tr("Hello, dialog!"));
dialog->show();
如果你足夠細心,應該發(fā)現(xiàn)上面的代碼是有問題的:dialog 存在內(nèi)存泄露!dialog 使用 new 在堆上分配空間,卻一直沒有 delete。解決方案也很簡單:將 MainWindow 的指針賦給 dialog 即可。還記得我們前面說過的 Qt 的對象系統(tǒng)嗎?
不過,這樣做有一個問題:如果我們的對話框不是在一個界面類中出現(xiàn)呢?由于QWidget的 parent 必須是QWidget指針,那就限制了我們不能將一個普通的 C++ 類指針傳給 Qt 對話框。另外,如果對內(nèi)存占用有嚴格限制的話,當我們將主窗口作為 parent 時,主窗口不關閉,對話框就不會被銷毀,所以會一直占用內(nèi)存。在這種情景下,我們可以設置 dialog 的WindowAttribute:
QDialog *dialog = new QDialog;
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->setWindowTitle(tr("Hello, dialog!"));
dialog->show();
setAttribute()函數(shù)設置對話框關閉時,自動銷毀對話框。
消息對話框
QMessageBox用于顯示消息提示。我們一般會使用其提供的幾個 static 函數(shù):
- 顯示關于對話框。
void about(QWidget * parent, const QString & title, const QString & text)
這是一個最簡單的對話框,其標題是 title,內(nèi)容是 text,父窗口是 parent。對話框只有一個 OK 按鈕。
- 顯示關于 Qt 對話框。該對話框用于顯示有關 Qt 的信息。
void aboutQt(QWidget * parent, const QString & title = QString()):
-
顯示嚴重錯誤對話框。
StandardButton critical(QWidget * parent, const QString & title, const QString & text, StandardButtons buttons = Ok, StandardButton defaultButton = NoButton):
這個對話框?qū)@示一個紅色的錯誤符號。我們可以通過 buttons 參數(shù)指明其顯示的按鈕。默認情況下只有一個 Ok 按鈕,我們可以使用StandardButtons類型指定多種按鈕。
- 與QMessageBox::critical()類似,不同之處在于這個對話框提供一個普通信息圖標。
StandardButton information(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton = NoButton)
- 與QMessageBox::critical ()類似,不同之處在于這個對話框提供一個問號圖標,并且其顯示的按鈕是“是”和“否”。
StandardButton question(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = StandardButtons( Yes | No ),
StandardButton defaultButton = NoButton)
- 與QMessageBox::critical()類似,不同之處在于這個對話框提供一個黃色嘆號圖標。
StandardButton warning(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton = NoButton)
我們可以通過下面的代碼來演示下如何使用QMessageBox。
if (QMessageBox::Yes == QMessageBox::question(this,
tr("Question"), tr("Are you OK?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes))
{
QMessageBox::information(this, tr("Hmmm..."),
tr("I'm glad to hear that!"));
}
else
{
QMessageBox::information(this, tr("Hmmm..."),
tr("I'm sorry!"));
}
我們使用QMessageBox::question()來詢問一個問題。
- 這個對話框的父窗口是 this。
QMessageBox是QDialog的子類,這意味著它的初始顯示位置將會是在 parent 窗口的中央。
-
第二個參數(shù)是對話框的標題。
-
第三個參數(shù)是我們想要顯示的內(nèi)容。
-
第四個參數(shù)是關聯(lián)的按鍵類型,我們可以使用或運算符(|)指定對話框應該出現(xiàn)的按鈕。比如我們希望是一個 Yes 和一個 No。
-
最后一個參數(shù)指定默認選擇的按鈕。
這個函數(shù)有一個返回值,用于確定用戶點擊的是哪一個按鈕。按照我們的寫法,應該很容易的看出,這是一個模態(tài)對話框,因此我們可以直接獲取其返回值。
QMessageBox類的 static 函數(shù)優(yōu)點是方便使用,缺點也很明顯:非常不靈活。我們只能使用簡單的幾種形式。為了能夠定制QMessageBox細節(jié),我們必須使用QMessageBox的屬性設置 API。如果我們希望制作一個詢問是否保存的對話框,我們可以使用如下的代碼:
QMessageBox msgBox;
msgBox.setText(tr("The document has been modified."));
msgBox.setInformativeText(tr("Do you want to save your changes?"));
msgBox.setDetailedText(tr("Differences here..."));
msgBox.setStandardButtons(QMessageBox::Save
? | QMessageBox::Discard
? | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Save:
qDebug() << "Save document!";
break;
case QMessageBox::Discard:
qDebug() << "Discard changes!";
break;
case QMessageBox::Cancel:
qDebug() << "Close document!";
break;
}
msgBox 是一個建立在棧上的QMessageBox實例。我們設置其主要文本信息為“The document has been modified.”,informativeText 則是會在對話框中顯示的簡單說明文字。下面我們使用了一個detailedText,也就是詳細信息,當我們點擊了詳細信息按鈕時,對話框可以自動顯示更多信息。我們自己定義的對話框的按鈕有三個:保存、丟棄和取消。然后我們使用了exec()是其成為一個模態(tài)對話框,根據(jù)其返回值進行相應的操作。
標準文件對話框
QFileDialog,也就是文件對話框。在本節(jié)中,我們將嘗試編寫一個簡單的文本文件編輯器,我們將使用QFileDialog來打開一個文本文件,并將修改過的文件保存到硬盤。
首先,我們需要創(chuàng)建一個帶有文本編輯功能的窗口。借用我們前面的程序代碼,應該可以很方便地完成:
openAction = new QAction(QIcon(":/images/file-open"),tr("&Open..."), this);
openAction->setStatusTip(tr("Open an existing file"));
saveAction = new QAction(QIcon(":/images/file-save"), tr("&Save..."), this);
saveAction->setStatusTip(tr("Save a new file"));
QMenu *file = menuBar()->addMenu(tr("&File"));
file->addAction(openAction);
file->addAction(saveAction);
QToolBar *toolBar = addToolBar(tr("&File"));
toolBar->addAction(openAction);
toolBar->addAction(saveAction);
textEdit = new QTextEdit(this);
setCentralWidget(textEdit);
我們在菜單和工具欄添加了兩個動作:打開和保存。接下來是一個QTextEdit類,這個類用于顯示富文本文件。也就是說,它不僅僅用于顯示文本,還可以顯示圖片、表格等等。不過,我們現(xiàn)在只用它顯示純文本文件。QMainWindow有一個setCentralWidget()函數(shù),可以將一個組件作為窗口的中心組件,放在窗口中央顯示區(qū)。顯然,在一個文本編輯器中,文本編輯區(qū)就是這個中心組件,因此我們將QTextEdit作為這種組件。
我們使用connect()函數(shù),為這兩個QAction對象添加響應的動作:
connect(openAction, &QAction::triggered,
this, &MainWindow::openFile);
connect(saveAction, &QAction::triggered,
this, &MainWindow::saveFile);
下面是最主要的openFile()和saveFile()這兩個函數(shù)的代碼:
//打開文件
void MainWindow::openFile()
{
QString path = QFileDialog::getOpenFileName(this,
? tr("Open File"), ".", tr("Text Files(*.txt)"));
if(!path.isEmpty())
{
? QFile file(path);
? if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
? QMessageBox::warning(this, tr("Read File"),
? tr("Cannot open file:\n%1").arg(path));
? return;
? }
? QTextStream in(&file);
? textEdit->setText(in.readAll());
? file.close();
}
else
{
? QMessageBox::warning(this, tr("Path"),
? tr("You did not select any file."));
}
}
//保存文件
void MainWindow::saveFile()
{
QString path = QFileDialog::getSaveFileName(this,
? tr("Open File"), ".", tr("Text Files(*.txt)"));
if(!path.isEmpty())
{
? QFile file(path);
? if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
? QMessageBox::warning(this, tr("Write File"),
? tr("Cannot open file:\n%1").arg(path));
? return;
? }
? QTextStream out(&file);
? out << textEdit->toPlainText();
? file.close();
}
else
{
? QMessageBox::warning(this, tr("Path"),
? tr("You did not select any file."));
}
}
在openFile()函數(shù)中,我們使用QFileDialog::getOpenFileName()來獲取需要打開的文件的路徑。這個函數(shù)原型如下:
QString getOpenFileName(QWidget * parent = 0,
? const QString & caption = QString(),
? const QString & dir = QString(),
? const QString & filter = QString(),
? QString * selectedFilter = 0,
? Options options = 0)
不過注意,它的所有參數(shù)都是可選的,因此在一定程度上說,這個函數(shù)也是簡單的。這六個參數(shù)分別是:
- parent:父窗口。
Qt 的標準對話框提供靜態(tài)函數(shù),用于返回一個模態(tài)對話框;
-
caption:對話框標題;
-
dir:對話框打開時的默認目錄
-
- “.” 代表程序運行目錄
- “/” 代表當前盤符的根目錄(特指 Windows 平臺;Linux 平臺當然就是根目錄),這個參數(shù)也可以是平臺相關的,比如“C:\”等;
-
filter:過濾器。
我們使用文件對話框可以瀏覽很多類型的文件,但是,很多時候我們僅希望打開特定類型的文件。比如,文本編輯器希望打開文本文件,圖片瀏覽器希望打開圖片文件。過濾器就是用于過濾特定的后綴名。如果我們使用“Image Files(.jpg .png)”,則只能顯示后綴名是 jpg 或者 png 的文件。如果需要多個過濾器,使用“;;”分割,比如“JPEG Files(.jpg);;PNG Files(.png)”;
-
selectedFilter:默認選擇的過濾器;
-
options:對話框的一些參數(shù)設定
比如只顯示文件夾等等,它的取值是enum QFileDialog::Option,每個選項可以使用 | 運算組合起來。
**QFileDialog::getOpenFileName()返回值是選擇的文件路徑。**我們將其賦值給 path。通過判斷 path 是否為空,可以確定用戶是否選擇了某一文件。只有當用戶選擇了一個文件時,我們才執(zhí)行下面的操作。文章來源:http://www.zghlxwxcb.cn/news/detail-683665.html
在saveFile()中使用的QFileDialog::getSaveFileName()也是類似的。使用這種靜態(tài)函數(shù),在 Windows、Mac OS 上面都是直接調(diào)用本地對話框,但是 Linux 上則是QFileDialog自己的模擬。這暗示了,如果你不使用這些靜態(tài)函數(shù),而是直接使用QFileDialog進行設置,那么得到的對話框很可能與系統(tǒng)對話框的外觀不一致。這一點是需要注意的。文章來源地址http://www.zghlxwxcb.cn/news/detail-683665.html
到了這里,關于QT基礎教程之五對話框QDialog的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!