上一篇開發了文本編輯器界面,在這一篇以及接下來的幾篇中,將對文本編輯器界面開發過程中涉及的所有動作集對應的功能項進行設計。本篇對文本編輯器的窗口標題設置、文件保存和關閉程序時的保存提醒功能進行講解。此外,還包括過QTextEdit類、標準文件對話框和消息框的相關使用。
本篇目錄1. 設置窗口標題
2. 保存文件
3. 關閉程序時的保存提醒
運行環境:
win 10 + Qt 5.12.5 + Qt Creator 4.10
1. 設置窗口標題在《【文本編輯器】一、界面設計》中通過setWindowTitle(tr("文本編輯器"));設置窗口標題,不過這只是應用程式的名稱。常見軟體的標題條通常設置成「文件名 - 軟體名」的形式,下面將按照這一標題形式設置文本編輯器的窗口標題。
在 "textedit.h" 文件中添加設置文本編輯器標題的函數和標題變量的聲明,代碼如下:
1private:
2 void setCurrentFileName(const QString &fileName); // 設置當前文件標題
3 QString fileName; // 當前文件標題名
在源文件中添加函數setCurrentFileName()的實現
1void TextEdit::setCurrentFileName(const QString &fileName)
2{
3 this->fileName = fileName; // 當前文檔名
4 textEdit->document()->setModified(false); // 默認文檔未被修改
5
6 QString shownName; // 標題條顯示的文檔名
7 if (fileName.isEmpty())
8 shownName = "未命名.txt";
9 else
10 shownName = QFileInfo(fileName).fileName();
11 // 設置窗口標題,當文檔被修改後使用星號 '*' 標記
12 setWindowTitle(tr("%1[*] - %2").arg(shownName, tr("文本編輯器")));
13 setWindowModified(false); // 默認標題中不顯示星號*
14}
上面的代碼中,textEdit->document()->setModified()用於設置文檔是否修改過,一般用於關閉時提示保存。QFileInfo(fileName).fileName()用於從文件路徑中提取文件名,這裡使用了QFileInfo類,需要添加頭文件
在構造函數中添加setCurrentFileName(QString())函數,創建窗口初始標題
1setCurrentFileName(QString());
運行程序後的效果如下
此時在文本編輯器中隨意輸入一些文字,窗口標題並沒有如期出現星號 '*' 標記,在構造函數中再加上如下代碼
1connect(textEdit->document(), &QTextDocument::modificationChanged,
2 this, &QWidget::setWindowModified);
用來連接文本編輯窗口和窗口標題,文本編輯窗口的內容被更改時,使用QTextEdit類的document()函數獲取QTextDocument類對象,發出文檔被修改信號函數modificationChanged()。然後使用setWindowModified()函數設置窗口的更改狀態標誌(星號 『*』),如果參數為true,則在標題中設置了星號 '[*]' 標誌的地方顯示 '*' 號,表示該文件已被修改。運行程序後效果如下
2. 保存文件保存文件功能分為『保存』或『另存為』兩種操作,在 "textedit.h" 文件中添加函數聲明:
1private slots:
2 bool fileSave();
3 bool fileSaveAs();
在對應的源文件中添加頭文件
1#include <QFileDialog>
2#include <QTextDocumentWriter>
文件保存的邏輯是先通過文件名判斷文件是否符合保存的條件,符合則將文件保存至原路徑下,否則則執行『另存為』操作。下面是保存函數的代碼:
1bool TextEdit::fileSave()
2{
3 // 若未命名文件名或文件名者以 ':/' 開頭,則直接執行另存為操作
4 if (fileName.isEmpty())
5 return fileSaveAs();
6 if (fileName.startsWith(QStringLiteral(":/")))
7 return fileSaveAs();
8
9 QTextDocumentWriter writer(fileName);
10 bool success = writer.write(textEdit->document());
11 // 在狀態欄顯示是否保存成功的提示信息
12 if (success) {
13 textEdit->document()->setModified(false);
14 statusBar()->showMessage(tr("已寫入 \"%1\"")
15 .arg(QDir::toNativeSeparators(fileName)));
16 } else {
17 statusBar()->showMessage(tr("未能寫入 \"%1\"")
18 .arg(QDir::toNativeSeparators(fileName)));
19 }
20 return success;
21}
代碼中QTextDocumentWriter類提供了與格式無關的接口,用於將QTextDocument寫入文件或其他設備。
QTextDocumentWriter writer(fileName);構造一個QTextDocumentWriter對象,該對象將使用指定的文檔格式寫入名稱為fileName的文件。如果未提供格式,則QTextDocumentWriter將通過檢查fileName的擴展名來檢測文檔格式。
另存為函數的實現流程是:新建保存形式的標準文件對話框;設置保存時默認的文件名後綴;將選擇的另存為路徑名賦給窗口標題設置函數。另存為函數的代碼如下:
1bool TextEdit::fileSaveAs()
2{
3 QFileDialog fileDialog(this, tr("另存為...")); // 新建標準文件對話框
4 fileDialog.setAcceptMode(QFileDialog::AcceptSave);
5 QStringList mimeTypes;
6 mimeTypes << "application/vnd.oasis.opendocument.text" << "text/html" << "text/plain";
7 fileDialog.setMimeTypeFilters(mimeTypes); // 從 MIME 類型列表中設置文件對話框中使用的過濾器
8 fileDialog.setDefaultSuffix("odt"); // 如果未指定其他後綴,則將此後綴添加到文件名中
9 if (fileDialog.exec() != QDialog::Accepted)
10 return false;
11 const QString fn = fileDialog.selectedFiles().first(); // 包含對話框中所選文件的絕對路徑的第一個字符串
12 setCurrentFileName(fn);
13 return fileSave();
14}
函數fileDialog.setAcceptMode()設置對話框模式,主要有兩種
Constant分別表示打開對話框和保存對話框,默認為AcceptOpen模式。取消setupFileActions()函數中對『保存』和『另存為』動作的連接函數connect()的注釋
1void TextEdit::setupFileActions()
2{
3 // 文件主菜單動作集
4 ...
5 connect(actionSave, &QAction::triggered, this, &TextEdit::fileSave);
6 ...
7 connect(actionSaveAs, &QAction::triggered, this, &TextEdit::fileSaveAs);
8 ...
9}
運行程序,點擊『保存』或『另存為』或使用快捷鍵 "Ctrl+S",效果如下
3. 關閉程序時的保存提醒為了在關閉或退出應用程式時主動提醒用戶保存,還需要設計「關閉」事件的關閉邏輯。這裡通過一個maybeSave()函數來實現,在 "textedit.h" 文件中
1private:
2 bool maybeSave();
函數maybeSave()先判定文檔是否被修改過,若未被修改過則直接退出,否則彈出保存提示對話框,再根據用戶在對話框中的選擇判斷是否保存文件。函數的實現代碼如下:
1bool TextEdit::maybeSave()
2{
3 if (!textEdit->document()->isModified())
4 return true;
5 // 保存提醒消息框
6 const QMessageBox::StandardButton ret =
7 QMessageBox::warning(this, tr("文本編輯器"),
8 tr("文檔已被修改,是否將其保存?"),
9 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
10 // 根據對話框中的選擇判斷是否保存文件
11 if (ret == QMessageBox::Save)
12 return fileSave();
13 else if (ret == QMessageBox::Cancel)
14 return false;
15 return true;
16}
這裡還需要添加相關的頭文件
1#include <QCloseEvent>
2#include <QMessageBox>
在函數maybeSave()基礎上就可以設計「關閉」事件,若maybeSave()函數返回值為真,則關閉文本編輯器,否則就忽略該事件。在 "textedit.h" 文件中聲明關閉函數:
1protected:
2 void closeEvent(QCloseEvent *e) override;
實現代碼如下:
1void TextEdit::closeEvent(QCloseEvent *e)
2{
3 if (maybeSave())
4 e->accept();
5 else
6 e->ignore();
7}
此外,將「文件」菜單中退出動作通過連接函數connect()關聯到窗口關閉槽函數上,代碼如下
1connect(actionQuit, &QAction::triggered, this, &QWidget::close);
運行程序,在文本編輯器中輸入任意內容,然後點擊右上角的關閉或者依次單擊『文件』『退出』,或者使用快捷鍵 "Ctrl+Q",將會提示關閉提醒消息框,效果如下
小結本篇介紹了文本編輯器的窗口標題設置、文件保存(另存為)和關閉/退出程序時的保存提醒功能,
相關閱讀:
《【文本編輯器】一、界面設計》
《主要的窗體類和主窗體構成》
《Qt 模塊簡介》
《信號與槽》
《代碼化 UI 設計》