Qt MDI及其使用方法(詳解版)


統的應用程序設計中有多文檔界面(Multi-document Interface,MDI)應用程序,Qt 為設計 MDI 應用程序提供了支持。

本節的實例 samp6_4 是一個 MDI 應用程序,程序運行效果如圖 1 所示。


MDI 應用程序實例 samp6_4 的運行時界面
圖 1 MDI 應用程序實例 samp6_4 的運行時界面


MDI 應用程序就是在主窗口里創建多個同類型的 MDI 子窗口,這些 MDI 子窗口在主窗口里顯示,並共享主窗口上的工具欄和菜單等操作功能,主窗口上的操作都針對當前活動的 MDI 子窗口進行。

設計 MDI 應用程序需要在主窗口工作區放置一個 QMdiArea 作為子窗體的容器。實例 samp6_4 主窗口的工作區使用一個 QMdiArea 組件,實例的子窗口類是 QFormDoc,是一個使用 QPlainTextEdit 進行簡單文本顯示和編輯的窗體。

創建的 QFormDoc 窗體對象作為一個子窗口加入到 mdiArea 組件中。QMdiArea 組件類似於實例 samp6_3 中主窗口上的 tabWidget 組件,只是 QMdiArea 提供更加完備的功能。更改 MDI 的顯示模式,可以得到與實例 samp6_3 相似的以多頁組件管理的 MDI 界面效果。

文檔窗口類QFormDoc的設計

以可視化方式創建一個基於 QWidget 的類 QFormDoc,設計可視化界面時,只放置一個 QPlainTextEdit 組件,並以水平布局填充滿整個窗口。這里不再用可視化的方式設計 Action,因為 QFormDoc 窗口不需要創建自己的工具欄,而是使用主窗口上的工具欄按鈕對 QFormDoc 窗體上的 QPlainTextEdit 組件進行操作。

為 QFormDoc 添加一些用於文件打開和編輯操作的接口函數,QFormDoc 類的完整定義如下:

  1. class QFormDoc : public QWidget
  2. {
  3. Q_OBJECT
  4. private:
  5. QString mCurrentFile; //當前文件
  6. bool mFileOpened=false; //文件已打開
  7. public:
  8. explicit QFormDoc(QWidget *parent = 0);
  9. ~QFormDoc();
  10. void loadFromFile(QString& aFileName); //打開文件
  11. QString currentFileName();//返回當前文件名
  12. bool isFileOpened();//文件已經打開
  13. void setEditFont();//設置字體
  14. void textCut(); //cut
  15. void textCopy(); //copy
  16. void textPaste(); //paste
  17. private:
  18. Ui::QFormDoc *ui;
  19. };

這些接口函數是為了在主窗口里調用,實現對 MDI 子窗口的操作。實現代碼如下:

  1. QFormDoc::QFormDoc(QWidget *parent) :
  2. QWidget(parent),
  3. ui(new Ui::QFormDoc)
  4. {
  5. ui->setupUi(this);
  6. this->setWindowTitle("New Doc"); //窗口標題
  7. this->setAttribute(Qt::WA_DeleteOnClose); //關閉時自動刪除
  8. }
  9. QFormDoc::~QFormDoc()
  10. {
  11. //QMessageBox::information(this,"信息","文檔窗口被釋放");
  12. delete ui;
  13. }
  14. void QFormDoc::loadFromFile(QString &aFileName)
  15. {//打開文件
  16. QFile aFile(aFileName); //以文件方式讀出
  17. if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //以只讀文本方式打開文件
  18. {
  19. QTextStream aStream(&aFile); //用文本流讀取文件
  20. ui->plainTextEdit->clear();//清空
  21. ui->plainTextEdit->setPlainText(aStream.readAll()); //讀取文本文件
  22. aFile.close();//關閉文件
  23. mCurrentFile=aFileName;//保存當前文件名
  24. QFileInfo fileInfo(aFileName); //文件信息
  25. QString str=fileInfo.fileName(); //去除路徑后的文件名
  26. this->setWindowTitle(str);
  27. mFileOpened=true;
  28. }
  29. }
  30. QString QFormDoc::currentFileName()
  31. {
  32. return mCurrentFile;
  33. }
  34. bool QFormDoc::isFileOpened()
  35. { //文件是否已打開
  36. return mFileOpened;
  37. }
  38. void QFormDoc::setEditFont()
  39. {
  40. QFont font;
  41. font=ui->plainTextEdit->font();
  42. bool ok;
  43. font=QFontDialog::getFont(&ok,font);
  44. ui->plainTextEdit->setFont(font);
  45. }
  46. void QFormDoc::textCut()
  47. {
  48. ui->plainTextEdit->cut();
  49. }
  50. void QFormDoc::textCopy()
  51. {
  52. ui->plainTextEdit->copy();
  53. }
  54. void QFormDoc::textPaste()
  55. {
  56. ui->plainTextEdit->paste();
  57. }

注意作為 MDI 子窗口,不管其是否設置為關閉時刪除,在主窗口里關閉一個 MDI 子窗口時,都會刪除子窗口對象。

MDI 主窗口設計與子窗口的使用

主窗口界面設計

要在主窗口實現 MDI 功能,只需在主窗口的工作區放置一個 QMdiArea 組件。圖 2 是設計好的主窗口界面。


設計時的主窗口
圖 2 設計時的主窗口


在 UI 設計器里創建 Action,並應用 Action 設計主工具欄。在主窗口的工作區放置一個 QMdiArea 組件,然后在主窗口的構造函數里設置 mdiArea 填充滿工作區。

  1. QWMainWindow::QWMainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::QWMainWindow)
  2. {
  3. ui->setupUi(this);
  4. this->setCentralWidget(ui->mdiArea);
  5. this->setWindowState(Qt::WindowMaximized);
  6. ui->mainToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderlcon);
  7. }

MDI 子窗口的創建與加入

下面是主窗口上“新建文檔”按鈕的響應代碼:

  1. void QWMainWindow::on_actDoc_New_triggered()
  2. { //新建文檔
  3. QFormDoc *formDoc = new QFormDoc(this);
  4. ui->mdiArea->addSubWindow (formDoc) ; //文檔窗口添力口到 MDI formDoc->show();
  5. }

代碼功能是新建一個 QFormDoc 類的窗口 formDoc,構造函數中傳入了主窗口指針,所以主窗口是 formDoc 的父窗口,然后使用 QMdiArea 的 addSubWindow() 函數將 formDoc 加入到 mdiArea。

下面是主窗口上“打開文檔”按鈕的響應代碼:

  1. void QWMainWindow::on_actDoc_Open_triggered()
  2. {//打開文件
  3. //必須先獲取當前MDI子窗口,再使用打開文件對話框,否則無法獲得活動的子窗口
  4. bool needNew=false;// 是否需要新建子窗口
  5. QFormDoc *formDoc;
  6. if (ui->mdiArea->subWindowList().count()>0) //如果有打開的主窗口,獲取活動窗口
  7. {
  8. formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();
  9. needNew=formDoc->isFileOpened();//文件已經打開,需要新建窗口
  10. }
  11. else
  12. needNew=true;
  13. QString curPath=QDir::currentPath();
  14. QString aFileName=QFileDialog::getOpenFileName(this,tr("打開一個文件"),curPath,
  15. "C程序文件(*.h *cpp);;文本文件(*.txt);;所有文件(*.*)");
  16. if (aFileName.isEmpty())
  17. return; //如果未選擇文件,退出
  18. if (needNew) //需要新建子窗口
  19. {
  20. formDoc = new QFormDoc(this);//指定父窗口,必須在父窗口為Widget窗口提供一個顯示區域
  21. ui->mdiArea->addSubWindow(formDoc);
  22. }
  23. formDoc->loadFromFile(aFileName); //打開文件
  24. formDoc->show();
  25. ui->actCut->setEnabled(true);
  26. ui->actCopy->setEnabled(true);
  27. ui->actPaste->setEnabled(true);
  28. ui->actFont->setEnabled(true);
  29. }

通過 QMdiArea::subWindowList() 可以獲得子窗口對象列表,從而可以判斷子窗口的個數。如果沒有一個MDI子窗口,就創建一個新的窗口並打開文件。

如果有 MDI 子窗口,則總有一個活動窗口,通過 QMdiArea::activeSubWindow() 可以獲得此活動的子窗口,通過子窗口的 isFileOpened() 函數判斷是否打開了文件,如果沒有打開過文件,就在這個活動窗口里打開文件,否則新建窗口打開文件。

注意一定要先獲取 MDI 子窗口,再使用 QFileDialog 選擇需要打開的文件。如果順序更換了,則無法獲得正確的 MDI 活動子窗口。

QMdiArea常用功能函數

QMdiArea 提供了一些成員函數,可以進行一些操作,工具欄上的“關閉全部”、“MDI模式”、“級聯展開”、“平鋪展開”等按鈕都是調用 QMdiArea 類的成員函數實現的。

下面是這幾個按鈕功能的實現代碼:

  1. void QWMainWindow::on_actCascade_triggered()
  2. { //窗口級聯展開
  3. ui->mdiArea->cascadeSubWindows();
  4. }
  5. void QWMainWindow::on_actTile_triggered()
  6. {//平鋪展開
  7. ui->mdiArea->tileSubWindows();
  8. }
  9. void QWMainWindow::on_actCloseALL_triggered()
  10. {//關閉全部子窗口
  11. ui->mdiArea->closeAllSubWindows();
  12. }
  13. void QWMainWindow::on_actViewMode_triggered(bool checked)
  14. {//MDI 顯示模式
  15. if (checked) //Tab多頁顯示模式
  16. {
  17. ui->mdiArea->setViewMode(QMdiArea::TabbedView); //Tab多頁顯示模式
  18. ui->mdiArea->setTabsClosable(true); //頁面可關閉
  19. ui->actCascade->setEnabled(false);
  20. ui->actTile->setEnabled(false);
  21. }
  22. else ////子窗口模式
  23. {
  24. ui->mdiArea->setViewMode(QMdiArea::SubWindowView); //子窗口模式
  25. ui->actCascade->setEnabled(true); //
  26. ui->actTile->setEnabled(true); //
  27. }
  28. }

其中,設置 MDI 視圖模式用 setViewMode() 函數,有兩種模式可以選擇:

  1. QMdiArea::Sub Window View 是傳統的子窗口模式,顯不效果如圖 1 所示。
  2. QMdiArea::TabbedView 是多頁的顯示模式,顯示效果如圖 3 所示。

多頁模式下 MDI 界面
圖 3 多頁模式下 MDI 界面

MDI的信號

QMdiArea 有一個信號 subWindowActivated(QMdiSubWindow *argl),在當前活動窗口切換時發射,利用此信號可以在活動窗口切換時進行一些處理,例如,在狀態欄里顯示活動 MDI 子窗口的文件名,在沒有 MDI 子窗口時,將工具欄上的編輯功能按鈕設置為禁用。

下面是該信號的槽函數代碼:

  1. void QWMainWindow::on_mdiArea_subWindowActivated(QMdiSubWindow *arg1)
  2. {//當前活動子窗口切換時
  3. if (ui->mdiArea->subWindowList().count()==0)
  4. { //若子窗口個數為零
  5. ui->actCut->setEnabled(false);
  6. ui->actCopy->setEnabled(false);
  7. ui->actPaste->setEnabled(false);
  8. ui->actFont->setEnabled(false);
  9. ui->statusBar->clearMessage();
  10. }
  11. else
  12. {
  13. QFormDoc *formDoc=static_cast<QFormDoc*>(ui->mdiArea->activeSubWindow()->widget());
  14. ui->statusBar->showMessage(formDoc->currentFileName()); //顯示主窗口的文件名
  15. }
  16. }

主窗口工具欄上的“剪切”、“復制”、“粘貼”、“字體設置”等按鈕都是調用當前子窗口的相應函數,關鍵是獲取當前 MDI 子窗體對象。

例如,“剪切”和“字體設置”按鈕的代碼如下:

    1. void QWMainWindow::on_actCut_triggered()
    2. { //cut
    3. QFormDoc* formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();
    4. formDoc->textCut();
    5. }
    6. void QWMainWindow::on_actFont_triggered()
    7. {//設置字體
    8. QFormDoc* formDoc=(QFormDoc*)ui->mdiArea->activeSubWindow()->widget();
    9. formDoc->setEditFont();
    10. }
    11.  
    12. 參考網址
    13. http://m.biancheng.net/view/1875.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM