Qt多窗口編程詳解


常用的窗體基類是 QWidget、QDialog 和 QMainWindow,在創建 GUI 應用程序時選擇窗體基類就是從這 3 個類中選擇。

QWidget 直接繼承於 QObject,是 QDialog 和 QMainWindow 的父類,其他繼承於 QWidget 的窗體類還有 QSplashScreen、QMdiSubWindow 和 QDesktopWidget。另外還有一個類 QWindow,它同時從 QObject 和 QSurface 繼承。這些類的繼承關系如圖 1 所示。

幾個窗體類的繼承關系
圖 1 幾個窗體類的繼承關系

這些窗體類的主要特點和用途如下:
  • QWidget:在沒有指定父容器時可作為獨立的窗口,指定父容器后可以作為容器的內部組件。
  • QDialog:用於設計對話框,以獨立窗口顯示。
  • QMainWindow:用於設計帶有菜單欄、工具欄、狀態欄的主窗口,一般以獨立窗口顯示。
  • QSplashScreen:用作應用程序啟動時的splash窗口,沒有邊框。
  • QMdiSubWindow:用於為 QMdiArea 提供一個子窗體,用於MDI(多文檔)應用程序的設計。
  • QDesktopWidget:具有多個顯卡和多個顯示器的系統具有多個桌面,這個類提供用戶桌面信息,如屏幕個數、每個屏幕的大小等。
  • QWindow:通過底層的窗口系統表示一個窗口的類,一般作為一個父容器的嵌入式窗體,不作為獨立窗體。

窗體類重要特性的設置

窗體顯示或運行的一些特性可以通過 QWidget 的一些函數設置,如在前面章節中,介紹對話框的創建和使用時,有如下的代碼:
  1. dlgLocate = new QWDialogLocate(this);
  2. dlgLocate->setAttribute(Qt::WA_DeleteOnClose);
  3. Qt::WindowFlags flags=dlgLocate->windowFlags();
  4. dlgLocate->setWindowFlags(flags | Qt::WindowStaysOnTopHint);
這段代碼就用到了兩個設置函數——setAttribute() 和 setWindowFlags(),它們可以設置窗體的顯示特性和運行特性。

下面介紹 QWidget 類中用於窗體屬性設置的幾個主要函數的功能。

setAttribute()函數

setAttribute() 函數用於設置窗體的一些屬性,其函數原型為:

void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on = true)

枚舉類型 Qt::WidgetAttribute 定義了窗體的一些屬性,可以打開或關閉這些屬性。枚舉類型 Qt::WidgetAttribute 常用的常量及其意義見表 2。

表 2 枚舉類型 QLWidgetAttribute 常用的常量
常量 意義
Qt:: WA_AcceptDrops 允許窗體接收拖放來的組件
Qt::WA_DeleteOnClose 窗體關閉時刪除自己,釋放內存
Qt::WA_Hover 鼠標進入或移出窗體時產生paint事件
Qt:: WAAcceptTouchEvents 窗體是否接受觸屏事件

setWindowFlags()函數

setWindowFlags() 函數用於設置窗體標記,其函數原型是:

void QWidget::setWindowFlags(Qt::WindowFlags type)

參數 type 是枚舉類型 Qt::WindowType 的值的組合,用於同時設置多個標記。

另外一個函數 setWindowFlag() 用於一次設置一個標記,其函數原型為:

void QWidget::setWindowFlag(Qt::WindowType flag, bool on = true)

可單獨打開或關閉某個屬性。枚舉類型 Qt::WindowType 常用的常量值見表 3。

表 3 枚舉類型 Qt::WindowType 常用的常量
常量 意義
表示窗體類型的常量
Qt::Widget 這是 QWidget 類的缺省類型。這種類型的窗體,如果它有父窗體,就作為父窗 體的子窗體;否則就作為一個獨立的窗口
Qt::Window 表明這個窗體是一個窗口,通常具有窗口的邊框、標題欄,而不管它是否有父窗體
Qt::Dialog 表明這個窗體是一個窗口,並且要顯示為對話框(例如在標題欄沒有最小化、 最大化按鈕)。這是 QDialog 類的缺省類型
Qt::Popup 表明這個窗體是用作彈出式菜單的窗體
Qt::Tool 表明這個窗體是工具窗體,具有更小的標題欄和關閉按鈕,通常作為工具欄的 窗體
Qt::ToolTip 表明這是用於 Tooltip 消息提示的窗體
Qt::SplashScreen 表明窗體是splash屏幕,是 QSplashScreen 類的缺省類型
Qt::Desktop 表明窗體是桌面,這是 QDesktopWidget 類的類型
Qt::SubWindow 表明窗體是子窗體,例如 QMdiSubWindow 就是這種類型
控制窗體顯示效果的常量
Qt::MSWindowsFixedSizeDialogHint 在 Windows 平台上,使窗口具有更窄的邊框,用於固定大小的對話框
Qt::FramelessWindowHint 創建無邊框窗口
WindowHint要定義窗體外觀定制窗體外觀的常量,需要先設置 Qt::Customize
Qt::CustomizeWindowHint 關閉缺省的窗口標題欄
Qt::WindowTitleHint 窗口有標題欄
Qt::WindowSystemMenuHint 有窗口系統菜單
Qt::WindowMinimizeButtonHint 有最小化按鈕
Qt::WindowMaximizeButtonHint 有最大化按鈕
Qt::WindowMinMaxButtonsHint 有最小化、最大化按鈕
Qt::WindowCloseButtonHint 有關閉按鈕
Qt::Windo wContextHelpButtonHint 有上下文幫助按鈕
Qt::WindowStaysOnTopHint 窗口總是處於最上層
Qt::WindowStaysOnBottomHint 窗口總是處於最下層
Qt::WindowTransparentForlnput 窗口只作為輸出,不接受輸入

Qt::Widget、Qt::Window 等表示窗體類型的常量可以使窗體具有缺省的外觀設置,如果設置為 Qt::Dialog 類型,則窗體具有對話框的缺省外觀,例如標題欄沒有最小化、最大化按鈕。

控制窗體顯示效果和外觀的設置項可定制窗體的外觀,例如設置一個窗體只有最小化最大化按鈕,沒有關閉按鈕。

setWindowState()函數

setWindowState() 函數使窗口處於最小化、最大化等狀態,其函數原型是:

void QWidget::setWindowState(Qt::WindowStates windowstate)

枚舉類型 Qt::WindowState 表示了窗體的狀態,其取值見表 4。

表 4 枚舉類型 Qt::WindowState 的常量
常量 意義
Qt: :WindowNoState 正常狀態
Qt: :WindowMinimized 窗口最小化
Qt:: WindowMaximized 窗口最大化
Qt::WindowFullScreen 窗口填充整個屏幕,而且沒有邊框
Qt:: Window Active 變為活動的窗口,例如可以接收鍵盤輸入

setWindowModality()函數

setWindowModality() 函數用於設置窗口的模態,只對窗口類型有用。其函數原型為:

void setWindowModality(Qt::WindowModality windowModality)

枚舉類型 Qt::WindowModality 的取值意義見表 5。

表 5 枚舉類型Qt::WindowModality的常量
常量 意義
Qt::NonModal 無模態,不會阻止其他窗口的輸入
Qt::WindowModal 窗口對於其父窗口、所有的上級父窗口都是模態的
Qt::ApplicationModal 窗口對整個應用程序是模態的,阻止所有窗口的輸入

setWindowOpacity()函數

setWindowOpacity() 函數用於設置窗口的透明度,其函數原型如下:

void QWidget::setWindowOpacity(qreal level)

參數 level 是 1.0(完全不透明)至 0.0(完全透明)之間的數。窗口透明度缺省值是 1.0,即完全不透明。

多窗口應用程序的設計

主窗口設計

本節以實例 samp6_3 演示多窗口應用程序的設計,實例主窗口如圖 6 所示。

實例samp6_3的主窗口
圖 6 實例samp6_3的主窗口

程序的主窗口類是 QWMainWindow,從 QMainWindow 繼承。主窗口有一個工具欄,4 個創建窗體的按鈕以不同方式創建和使用窗體。主窗體工作區繪制一個背景圖片,有一個 tabWidget 組件,作為創建窗體的父窗體。沒有子窗體時,tabWidget 不顯示。

下面是 QWMainWindow 的構造函數和繪制背景圖片的代碼:
  1. QWMainWindow::QWMainWindow(QWidget *parent) :
  2. QMainWindow(parent),
  3. ui(new Ui::QWMainWindow)
  4. {
  5. ui->setupUi(this);
  6. ui->tabWidget->setVisible(false);
  7. ui->tabWidget->clear();//清除所有頁面
  8. ui->tabWidget->tabsClosable(); //Page有關閉按鈕,可被關閉
  9. this->setCentralWidget(ui->tabWidget);
  10. this->setWindowState(Qt::WindowMaximized); //窗口最大化顯示
  11. this->setAutoFillBackground(true);
  12. }
  13. void QWMainWindow::paintEvent(QPaintEvent *event)
  14. { //繪制窗口背景圖片
  15. Q_UNUSED(event);
  16. QPainter painter(this);
  17. painter.drawPixmap(0,ui->mainToolBar->height(),this->width(),this->height()-ui->mainToolBar->height()-ui->statusBar->height(),QPixmap(":/images/images/back2.jpg"));
  18. }
在構造函數中,將 tabWidget 組件設置為不可見,並且頁面可關閉,這樣每個頁面標題部分都會出現一個關閉按鈕,單擊可以關閉頁面。

背景圖片繪制使用窗體的 paintEvent() 事件,獲取主窗口的畫筆之后,將資源文件里的一個圖片繪制在主窗口的工作區。繪圖的內容在后續章節中詳細介紹。

實例除了主窗口之外,還有兩個窗口和兩個對話框:
  • QFormDoc:是繼承於 QWidget 可視化設計的窗體,主窗口工具欄上的“嵌入式 Widget”和“獨立 Widget 窗口”按鈕將以兩種方式使用 QFormDoc 類。
  • QFormTable:是繼承於 QMainWindow 可視化設計的窗體,其界面功能與實例 samp6_2 的主窗口類似,主窗口工具欄上的“嵌入式 MainWindow”和“獨立 MainWindow 窗口”按鈕將以兩種方式使用 QFormTable 類。
  • QWDialogSize 和 QWDialogHeaders 就是實例 samp6_2 中設計的對話框類,由 QFormTable 調用進行表格組件設置。

QFormDoc類的設計

在 Qt Creator 單擊 File->New File or Project 菜單項,在出現的對話框里選擇創建 Qt Designer Form Class,並且在向導中選擇基類為 QWidget,將創建的新類命名為 QFormDoc。

在 QFormDoc 的窗口上只放置一個 QPlainTextEdit 組件。由於 QFormDoc 是從 QWidget 繼承而來的,在 UI 設計器里不能直接為 QFormDoc 設計工具欄,但是可以創建 Action,然后在窗體創建時用代碼創建工具欄。

QFormDoc 窗口設計的 Action
圖 7 QFormDoc 窗口設計的 Action

圖 7 是設計的 Action 除了 actOpen 和 actFont 之外,其他編輯操作的 Action 都和 QPlainTextEdit 相關槽函數關聯,actClose 與窗口的 close() 槽函數關聯。

actOpen 用於打開文件,actFont 用於設置文檔字體,這些功能在前面的例子里都遇到過,不是本實例的重點,不再介紹其實現代碼。

在 QFormDoc 的構造函數里用代碼創建工具欄和布局,也可以在析構函數里增加一個消息顯示的對話框,以便觀察窗體是何時被刪除的。代碼如下:
  1. QFormDoc::QFormDoc(QWidget *parent) :
  2. QWidget(parent),
  3. ui(new Ui::QFormDoc)
  4. {
  5. ui->setupUi(this);
  6. //使用UI設計的Actions設計工具欄
  7. QToolBar* locToolBar = new QToolBar(tr("文檔"),this); //創建工具欄
  8. locToolBar->addAction(ui->actOpen);
  9. locToolBar->addAction(ui->actFont);
  10. locToolBar->addSeparator();
  11. locToolBar->addAction(ui->actCut);
  12. locToolBar->addAction(ui->actCopy);
  13. locToolBar->addAction(ui->actPaste);
  14. locToolBar->addAction(ui->actUndo);
  15. locToolBar->addAction(ui->actRedo);
  16. locToolBar->addSeparator();
  17. locToolBar->addAction(ui->actClose);
  18. locToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
  19. QVBoxLayout *Layout = new QVBoxLayout();
  20. Layout->addWidget(locToolBar); //設置工具欄和編輯器上下布局
  21. Layout->addWidget(ui->plainTextEdit);
  22. Layout->setContentsMargins(2,2,2,2); //減小邊框的寬度
  23. Layout->setSpacing(2);
  24. this->setLayout(Layout); //設置布局
  25. }
  26. QFormDoc::~QFormDoc()
  27. {
  28. QMessageBox::information(this, "消息", "QFormDoc對象被刪除和釋放");
  29. delete ui;
  30. }

QFormDoc類的使用

主窗口工具欄上的“嵌入式 Widget”按鈕的響應代碼如下:
  1. void QWMainWindow::on_actWidgetInsite_triggered()
  2. {
  3. //創建QFormDoc窗體,並在tabWidget中顯示
  4. QFormDoc *formDoc = new QFormDoc(this);
  5. formDoc->setAttribute (Qt: : WA_DeleteOnClose) ; //關閉時自動刪除
  6. int cur=ui->tabWidget->addTab(formDoc,QString::asprintf("Doc %d",ui->tabWidget->count()));
  7. ui->tabWidget->setCurrentIndex(cur);
  8. ui->tabWidget->setVisible(true);
  9. }
這段代碼動態創建一個 QFormDoc 類對象 formDoc,並設置其為關閉時刪除。然后使用 QTabWidget 的 addTab() 函數,為主窗口上的 tabWidget 新建一個頁面,作為 formDoc 的父窗體組件,formDoc 就在新建的頁面里顯示,我們稱這種窗體顯示方式為“嵌入式”。

主窗口工具欄上的“獨立 Widget 窗口”按鈕響應代碼如下:
  1. void QWMainWindow::on_actWidget_triggered()
  2. {
  3. QFormDoc *formDoc = new QFormDoc(); //不指定父窗口,用show()顯示
  4. formDoc->setAttribute(Qt::WA_DeleteOnClose); //關閉時自動刪除
  5. formDoc->setWindowTitle("基於QWidget的窗體,無父窗口,關閉時刪除");
  6. formDoc->setWindowFlag(Qt::Window,true);
  7. //formDoc->setWindowFlag(Qt::CustomizeWindowHint,true);
  8. //formDoc->setWindowFlag(Qt::WindowMinMaxButtonsHint,true);
  9. //formDoc->setWindowFlag(Qt::WindowCloseButtonHint,true);
  10. //formDoc->setWindowFlag(Qt::WindowStaysOnTopHint,true);
  11. //formDoc->setWindowState(Qt::WindowMaximized);
  12. formDoc->setWindowOpacity(0.9);
  13. //formDoc->setWindowModality(Qt::WindowModal);
  14. formDoc->show(); //在單獨的窗口中顯示
  15. }
這里在創建 formDoc 對象時,並沒有指定父窗口,創建窗口的代碼是:

QFormDoc *formDoc = new QFormDoc();

使用 setWindowFlag() 函數,設置其為 Qt::Window 類型,並用 show() 函數顯不窗口。這樣創建的是一個單獨顯示的窗口,並且在 windows 的任務欄上會有顯示。若有文檔窗口打開,則關閉主窗口,而文檔窗口依然存在,實際上這時候主窗口是隱藏了。若關閉所有文檔窗口,主窗口自動刪除並釋放,才完全關閉應用程序。

如果創建 formDoc 時指定主窗口為父窗口,即:

QFormDoc *formDoc = new QFormDoc(this);

則 formDoc 不會在 windows 的任務欄上顯示,關閉主窗口時,所有文檔窗口自動刪除。

圖 8 是嵌入式和獨立的 QFormDoc 窗體的顯示效果,在創建獨立的顯示窗口時,還可以嘗試使用 setWindowFlag() 函數設置不同的屬性,觀察這些屬性的控制效果。

嵌入式和獨立的 QFormDoc 窗體顯示效果
圖 8 嵌入式和獨立的 QFormDoc 窗體顯示效果

QFormTable類的設計

表格窗口類 QFormTable 是基於 QMainWindow 的可視窗口類,其功能與實例 samp6_2 主窗口類似,使用 QStandardltemModel 模型和 QTableView 組件構成 Model/View 結構的表格數據編輯器,並且可以調用 QWDialogSize 和 QWDialogHeaders 對話框進行表格大小設置和表頭設置。

該窗口的具體設計不詳細介紹了,只是為了觀察窗口刪除的時機,在析構函數里增加一個信息顯示對話框:
  1. QFormTable::〜QFormTable()
  2. {
  3. QMessageBox::information (this, "消息","FormTable 窗口被刪除和釋放"); delete ui;
  4. }

QFormTable類的使用

主窗口工具欄上的“嵌入式 MainWindow”按鈕的響應代碼如下:
  1. void QWMainWindow::on_actWindowInsite_triggered()
  2. {
  3. QFormTable *formTable = new QFormTable(this);
  4. formTable->setAttribute(Qt::WA_DeleteOnClose); //關閉時自動刪除
  5. int cur=ui->tabWidget->addTab(formTable,QString::asprintf("Table %d",ui->tabWidget->count()));
  6. ui->tabWidget->setCurrentIndex(cur);
  7. ui->tabWidget->setVisible(true);
  8. }
代碼功能是創建一個 QFormTable 對象 formTable,並在主窗口的 tabWidget 組件里新增一個頁面,將 formTable 顯示在新增頁面里。所以,即使是從 QMainWindow 繼承的窗口類,也是可以在其他界面組件里嵌入式顯示的。

主窗口工具欄上的“獨立 MainWindow 窗口”按鈕響應代碼如下:
  1. void QWMainWindow::on_actWindow_triggered()
  2. {
  3. QFormTable* formTable = new QFormTable(this);
  4. formTable->setAttribute(Qt::WA_Delete〇nClose);
  5. formTable->setWindowTitle ("基於 QMainWindow 的窗口,指定父窗口,關閉時刪除");
  6. formTable->show();
  7. }
這樣創建的 formTable 以獨立窗口顯示,關閉時自動刪除。它指定了主窗口為父窗口,主窗口關閉時,所有 QFormTable 類窗口自動刪除。

無論是嵌入式的,還是獨立的 QFormTable 窗口,都可以調用 QWDialogSize 和 QWDialogHeaders 對話框進行表格大小和表頭文字設置,對話框的調用方法在前面章節己有介紹。創建 QFormTable 嵌入式窗體和獨立窗口的運行效果如圖 9 所示。

嵌入式和獨立的QFormDoc窗體顯示效果
圖 9 嵌入式和獨立的QFormDoc窗體顯示效果

QTabWidget類的控制

現在,單擊 tabWidget 中嵌入的 QFormDoc 或 QFormTable 窗體工具欄上的“關閉”按鈕,都可以關閉窗體並且刪除分頁。但是單擊分頁上的關閉圖標,並不能關閉窗口。而且,關閉所有分頁后,tabWidget 並沒有隱藏,無法顯示背景圖片。

為此,需要對 tabWidget 的兩個信號編寫槽函數,tabCloseRequested() 和 currentChanged() 信號的槽函數代碼如下:
  1. void QWMainWindow::on_tabWidget_tabCloseRequested(int index)
  2. {//關閉Tab
  3. if (index<0)
  4. return;
  5. QWidget* aForm=ui->tabWidget->widget(index);
  6. aForm->close();
  7. }
  8. void QWMainWindow::on_tabWidget_currentChanged(int index)
  9. {
  10. bool en=ui->tabWidget->count()>0; //再無頁面時,actions禁用
  11. ui->tabWidget->setVisible(en);
  12. }
tabCloseRequested() 信號在單擊分頁的關閉圖標時發射,傳遞來的參數 index 表示頁面的編號。QTabWidget::widget() 返回 TabWidget 組件中某個頁面的窗體組件。獲取頁面的 QWidget 組件后,調用 close() 函數關閉窗體。

刪除一個分頁或切換頁面時,會發射 currentChanged() 信號,在此信號的槽函數里判斷分頁個數是否為零,以控制 tabWidget 是否可見。


免責聲明!

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



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