【转】17.Qt界面布局管理详解
在上一節,通過一個簡單的應用程序,分析了?Qt?創建的 GUI 應用程序中各個文件的作用,剖析了可視化設計的UI文件是如何被轉換為?C++?的類定義,并自動創建界面的。這些是使用 Qt Creator 可視化設計用戶界面,并使各個部分融合起來運行的基本原理。
本節再以一個稍微復雜的例子來講解設計 GUI 的常見功能,包括界面設計時布局的管理,以及程序里如何訪問界面組件。
實例程序功能
創建一個 Widget Application 項目 samp2_2,在創建窗體時選擇基類 QDialog,生成的類命名為 QWDialog,并選擇生成窗體。
如此新建的項目 samp2_2 有一個界面文件 qwdialog.ui,一個頭文件 qwdialog.h 和源程序文件 qwdialog.cpp。此外,還有項目文件 samp2_2.pro 和主程序文件 main.cpp。
qwdialog.ui 界面文件設計時界面如圖 1 所示。程序的主要功能是對中間一個文本框的文字字體樣式和顏色進行設置。
圖 1 實例程序 samp2_2 設計時界面
在界面設計時,對需要訪問的組件修改其 objectName,如各個按鈕、需要讀取輸入的編輯框、需要顯示結果的標簽等,以便在程序里區分。對于不需要程序訪問的組件則無需修改其 objectName,如用于界面上組件分組的 GroupBox、Frame、布局等,讓 UI 設計器自動命名即可。
對圖 1 中幾個主要組件的命名、屬性設置見表 2。
?
| txtEdit? | QPlainTextEdit | Text="Hello, World It is my demo. " Font.PointSize=20 | 用于顯示文字內容,可編輯 |
| chkBoxUnder? | QCheckBox? | Text="Underline" | 設置字體為下劃線 |
| chkBoxItalic? | QCheckBox? | Text="Italic" | 設置字體為斜體 |
| chkBoxBold? | QCheckBox? | Text="Bold" | 設置字體為粗體 |
| rBtnBlack? | QRadioButton? | Text="Black" | 字體顏色為黑色 |
| rBtnRed? | QRadioButton? | Text="Red" | 字體顏色為紅色 |
| rBtnBlue? | QRadioButton? | Text="Blue" | 字體顏色為藍色 |
| btnOK? | QPushButton? | Text="確定" | 返回確定,并關閉窗口 |
| btnCancel? | QPushButton? | Text="取消"? | 返回取消,并關閉窗口 |
| btnClose? | QPushButton? | Text="退出" | 退出程序 |
| QWDialog? | QWDialog? | windowTitle="Dialog by Designer" | 界面窗口的類名稱是QWDialog,objectName 不要修改 |
對于界面組件的屬性設置,需要注意以下幾點。
界面組件布局
Qt 的界面設計使用了布局(Layout)功能。所謂布局,就是界面上組件的排列方式,使用布局可以使組件有規則地分布,并且隨著窗體大小變化自動地調整大小和相對位置。布局管理是 GUI 設計的必備技巧,下面逐步講解如何實現圖 1 所示的界面設計。
界面組件的層次關系
為了將界面上的各個組件的分布設計得更加美觀,經常使用一些容器類,如 QgoupBox、QtabWidget、QFrame 等。
例如,將 3 個 CheckBox 組件放置在一個 GroupBox 組件里,該 GroupBox 組件就是這 3 個 CheckBox 的容器,移動這個 GroupBox 就會同時移動其中的 3 個 CheckBox。
圖 3 界面組件的放置及層次關系
圖 3 顯示的是設計圖 1 界面的前期階段。在窗體上放置了 2 個 GroupBox 組件,在 groupBox1 里放置 3 個 CheckBox 組件,在 groupBox2 里放置 3 個 RadioButton 組件。圖 3 右側 Object Inspector 里顯示了界面上各組件之間的層次關系。
布局管理
Qt 為界面設計提供了豐富的布局管理功能,在 UI 設計器中,組件面板里有 Layouts 和 Spacers 兩個組件面板,在窗體上方的工具欄里有布局管理的按鈕(如圖 4 所示)。
圖 4 用于布局可視化設計的組件面板和工具欄
Layouts 和 Spacers 兩個組件面板里的布局組件的功能見表 5:
?
| Vertical Layout | 垂直方向布局,組件自動在垂直方向上分布 |
| Horizontal Layout | 水平方向布局,組件自動在水平方向上分布 |
| Grid Layout | 網格狀布局,網狀布局大小改變時,每個網格的大小都改變 |
| Form Layout | 窗體布局,與網格狀布局類似,但是只有最右側的一列網格會改變大小 |
| Horizontal Spacer | 一個用于水平分隔的空格 |
| Vertical Spacer | 一個用于垂直分隔的空格 |
使用組件面板里的布局組件設計布局時,先拖放一個布局組件到窗體上,如在設計圖 4 中 3 個按鈕的布局時,先放一個 Horizontal Layout 到窗體上,布局組件會以紅色邊框顯示。再往布局組件里拖放 3 個 Push Button 和 2 個 Horizontal Spacer,就可以得到圖 1 中 3 個按鈕的水平布局效果。
在設計窗體的上方有一個工具欄,用于調整設計器進入不同的狀態,以及進行布局設計,工具欄上各按鈕的功能見表 6。
?
| Edit Widget (F3) | 界面設計進入編輯狀態,就是正常的設計狀態 |
| Edit Signals/Slots(F4)? | 進入信號與槽的可視化設計狀態 |
| Edit Buddies | 進入伙伴關系編輯狀態,可以設置一個Label 與一個組件成為伙伴關系 |
| Edit Tab Order | 進入Tab 順序編輯狀態,Tab 順序是在鍵盤上按Tab 鍵時,輸入焦點在界面各組件之間跳動的順序 |
| Lay Out Horizontally (Ctrl+H) | 將窗體上所選組件水平布局 |
| Lay Out Vertically (Ctrl+L)? | 將窗體上所選組件垂直布局 |
| Lay Out Horizontally in Splitter | 將窗體上所選組件用一個分割條進行水平分割布局 |
| Lay Out Vertically in Splitter | 將窗體上所選組件用一個分割條進行垂直分割布局 |
| Lay Out in a Form Layout | 將窗體上所選組件按窗體布局 |
| Lay Out in a Grid | 將窗體上所選組件網格布局 |
| Break Layout | 解除窗體上所選組件的布局,也就是打散現有的布局 |
| Adjust Size(Ctrl+J) | 自動調整所選組件的大小 |
使用工具欄上的布局控制按鈕時,只需在窗體上選中需要設計布局的組件,然后點擊某個布局按鈕即可。在窗體上選擇組件時同時按住 Ctrl 鍵,可以實現組件多選,選擇某個容器類組件,相當于選擇了其內部的所有組件。
例如,在圖 3 的界面中,選中 groupBox1,然后單擊“Lay Out Horizontally”工具欄按鈕,就可以對 groupBox1 內的 3 個 CheckBox 水平布局。
在圖 4 的界面上,使 groupBox1 里的 3 個 CheckBox 水平布局,groupBox2 里的 3 個 RadioButton 水平布局,下方 3個按鈕水平布局。在窗體上又放置了一個 PlainTextEdit 組件。現在,改變 groupBox1、groupBox2 或按鈕的水平布局的大小,其內部組件都會自動改變大小。但是當改變窗體大小時,界面上的各組件卻并不會自動改變大小。
隨后還需為窗體指定一個總的布局。選中窗體(即不要選擇任何組件),單擊工具欄上的“Lay Out Vertically”按鈕,使 4 個組件垂直分布。這樣布局后,當窗體大小改變時,各個組件都會自動改變大小。
在 UI 設計器里可視化設計布局時,要善于利用水平和垂直空格組件,善于設置組件的最大、最小寬度和高度來實現某些需要的布局效果。
伙伴關系與 Tab 順序
在 UI 設計工具欄上單擊“Edit Buddies”按鈕可以進入伙伴關系編輯狀態,如設計一個窗體時,進入伙伴編輯狀態之后的界面如圖 7 所示。
圖 7 編輯伙伴關系
伙伴關系(Buddy)是指界面上一個 Label 和一個組件相關聯,如圖 7 中的伙伴關系編輯狀態,單擊一個 Label,按住鼠標左鍵,然后拖向一個組件,就建立了 Label 和組件之間的伙伴關系。
伙伴關系是為了在程序運行時,在窗體上用快捷鍵快速將輸入焦點切換到某個組件上。例如,在圖 7 的界面上,設定“姓名”標簽的 Text 屬性為“姓名(&N)”,其中符號“&”用來指定快捷字符,界面上并不顯示“&”,這里指定快捷字母為 N。那么程序運行時,用戶按下?Alt+N,輸入焦點就會快速切換到“姓名”關聯的輸入框內。
圖 8 Tab 順序編輯狀態
在 UI 設計器工具欄上單擊“Edit Tab Order”按鈕進入Tab 順序編輯狀態(如圖 8 所示)。Tab 順序是指在程序運行時,按下鍵盤上的 Tab 鍵時輸入焦點的移動順序。一個好的用戶界面,在按 Tab 鍵時,焦點應該以合理的順序在界面上移動,而不是隨意地移動。
進入 Tab 順序編輯狀態后,在界面上會顯示具有 Tab 順序組件的編號,依次按希望的順序單擊組件,就可以重排 Tab 順序了。沒有輸入焦點的組件是沒有 Tab 順序的,如 Label 組件。
項目功能實現
下面開始設計程序功能。對于該程序,希望它的功能如下:
字體樣式設置
窗體在設計模式下,選中 chkBoxUnder 組件,單擊右鍵調出其快捷菜單。在快捷菜單中單擊菜單項“Go to slot…”(中文狀態為“轉到槽”),出現如圖 9 所示的對話框。
圖 9 QcheckBox的Go to slot對話框
該對話框列出了 QCheckBox 類的所有信號,第一個是 clicked(),第二個是帶一個布爾類型參數的 clicked(bool)。
信號 clicked(bool) 會將 CheckBox 組件當前的選擇狀態作為一個參數傳遞,在響應代碼里可以直接利用這個傳遞的參數。而如果用信號 clicked(),則需要在代碼里讀取 CheckBox 組件的選中狀態。為了簡化代碼,選擇 clicked(bool) 信號。
選擇 clicked(bool),然后單擊“OK”按鈕,在 QWDialog 的類定義中,會在 private slots 部分自動增加一個槽函數聲明,函數名是根據發射對象及其信號名稱自動命名的。
void on_chkBoxUnder_clicked(bool checked);
同時,在 qwdialog.cpp 文件中自動添加了函數 on_chkBoxUnder_clicked(bool) 的框架,在此函數中添加如下的代碼,實現文本框字體下劃線的控制。
void QWDialog::on_chkBoxUnder_clicked(bool checked) {QFont font=ui->txtEdit->font();font.setUnderline(checked);ui->txtEdit->setFont(font); }以同樣的方法為 Italic 和 Bold 兩個 CheckBox設計槽函數,編譯后運行,發現已經實現了修改字體的下劃線、斜體、粗體屬性的功能,說明信號與槽函數已經關聯了。
但是,查看 QWDialog 的構造函數,構造函數只有簡單的一條語句。
這里沒有發現用 connect() 函數進行幾個 CheckBox 的信號與槽函數關聯的操作。這些功能是如何實現的呢?
查看編譯生成的 ui_qwdialog.h 文件。構造函數里調用的 setupUi() 是在 ui_qwdialog.h 文件里實現的。查看 setupUi() 函數的內容,也沒有發現用 connect() 函數進行幾個 CheckBox 的信號與槽關聯的操作,只是在 setupUI()里發現了如下的一條語句:
QMetaObject::connectSlotsByName(QWDialog);
秘密就在于這條語句。connectSlotsByName(QWDialog) 函數將搜索 QWDialog 界面上的所有組件,將信號與槽函數匹配的信號和槽關聯起來,它假設槽函數的名稱是:
void on_<object name>_<signal name>(<signal parameters>);
例如,通過 UI 設計器的操作,為 chkBoxUnder 自動生成的槽函數是:
void on_chkBoxUnder_clicked(bool checked);
它就正好是 chkBoxUnder 的信號 clicked(bool) 的槽函數。那么,connectSlotsByName() 就會將此信號和槽函數關聯起來,如同執行了下面的這樣一條語句:
connect(chkBoxUnder, SIGNAL(clicked (bool)),
this, SLOT (on_chkBoxUnder_clicked (bool));
這就是用 UI 設計器可視化設計某個組件的信號響應槽函數,而不用手工去將其關聯起來的原因,都是在界面類的構造函數里調用 setupUi() 自動完成了關聯。
字體顏色設置
設置字體的 3 個 RadioButton 是互斥性選擇的,即一次只有一個 RadioButton 被選中,雖然也可以采用可視化設計的方式設計其 clicked() 信號的槽函數,但是這樣就需要生成 3 個槽函數。這里可以簡化設計,即設計一個槽函數,將 3 個 RadioButton 的 clicked() 信號關聯到這一個槽函數。
為此,在 QWDialog 類的 private slots 部分增加一個槽函數定義如下:
void setTextFontColor();
提示 將鼠標光標移動到這個函數的函數名上面,單擊右鍵,在彈出的快捷菜單中選擇“Refactor”→“Add Definition in qwdialog.cpp”,就可以在 qwdialog.cpp 文件中自動為函數 setTextFontColor() 生成一個函數框架。
在 qwdialog.cpp 文件中,為 setTextFontColor() 編寫實現代碼如下:
由于這個槽函數是自定義的,所以不會自動與 RadioButton 的 clicked() 事件關聯,此時編譯后運行程序不會實現改變字體顏色的功能。需要在 QWDialog 的構造函數中手工進行關聯,代碼如下:
QWDialog::QWDialog(QWidget *parent) : QDialog(parent), ui(new Ui::QWDialog) {ui->setupUi(this);connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor())); }在構造函數中將 3 個 RadioButton 的 clicked() 信號與同一個槽函數 setTextFontColor() 相關聯。再編譯后運行,就可以更改文字的顏色了。
三個按鈕的功能設計
界面上還有“確定”“取消”“退出”3 個按鈕,這是在對話框中常見的按鈕。“確定”表示確認選擇并關閉對話框,“取消”表示取消選擇并關閉對話框,“退出”則直接關閉對話框。
QWDialog 是從 QDialog 繼承而來的,QDialog 提供了 accept()、reject()、close() 等槽函數來表示這三種狀態,只需將按鈕的 clicked() 信號與相應槽函數關聯即可。
下面采用可視化的方式,將按鈕的 clicked() 信號與這些槽函數關聯起來。在 UI 設計器里,單擊上方工具欄里的“Edit Signals/Slots”按鈕,窗體進入信號與槽函數編輯狀態,如圖 10 所示。
圖 10 窗體進入Signals/Slot編輯狀態
將鼠標移動到“確定”按鈕上方,再按下鼠標左鍵,移動到窗體的空白區域釋放左鍵,這時出現如圖 11 所示的關聯設置對話框。
圖 11 信號與槽關聯編輯對話框
在圖 11 中,左側的列表框里顯示了 btnOK 的信號,選擇 clicked(),右邊的列表框里顯示了 QWDialog 的槽函數,選擇 accept(),單擊“OK”按鈕。
同樣的方法可以將 btnCancel 的 clicked() 信號與 QWDialog 的 reject() 槽函數關聯,將 btnClose 的 clicked() 信號與 QWDialog 的 close() 槽函數關聯。
注意,在圖 11 的右側列表框中沒有 close() 槽函數,需要勾選下方的“Show signals and slots inherited from QWidget”才會出現 close() 函數。
設置完 3 個按鈕的信號與槽關聯之后,在窗體下方的 Signals 和 Slots 編輯器里也顯示了這 3 個關聯。實際上,可以直接在 Signals 和 Slots 編輯器進行關聯設置。現在編譯并運行程序,單擊這 3 個按鈕都會關閉程序。
那么,這 3 個按鈕的信號與槽函數的關聯是在哪里實現的呢?答案在 setupUi() 函數里,在 setupUi() 函數里自動增加了以下 3 行代碼:
這個實例程序的功能全部完成了。采用 UI 設計器設計了窗體界面,采用可視化和程序化的方式設計槽函數,設計信號與槽函數之間的關聯。
從以上的設計過程可以看到,Qt Creator 和 UI 設計器為設計應用程序提供了強大的可視化設計功能。
總結
以上是生活随笔為你收集整理的【转】17.Qt界面布局管理详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017交通银行信用卡最红星期五加油站列
- 下一篇: 【转】控件通知消息