C++ Qt開發(fā):TabWidget實(shí)現(xiàn)多窗體功能
Qt 是一個(gè)跨平臺(tái)C++圖形界面開發(fā)庫(kù),利用Qt可以快速開發(fā)跨平臺(tái)窗體應(yīng)用程序,在Qt中我們可以通過拖拽的方式將不同組件放到指定的位置,實(shí)現(xiàn)圖形化開發(fā)極大的方便了開發(fā)效率,本章將重點(diǎn)介紹TabWidget標(biāo)簽組件的常用方法及靈活運(yùn)用。
QTabWidget 是Qt中用于實(shí)現(xiàn)標(biāo)簽頁(yè)(tabbed interface)的控件,可以在一個(gè)窗口內(nèi)切換不同的頁(yè)面。在開發(fā)窗體應(yīng)用時(shí)通常會(huì)伴隨功能的分頁(yè),使用TabWidget并配合自定義Dialog組件,即可實(shí)現(xiàn)一個(gè)復(fù)雜的多窗體分頁(yè)結(jié)構(gòu),此類布局方式也是多數(shù)軟件通用的方案。
以下是 QTabWidget 的一些常用方法,以表格形式概述:
| 方法簽名 | 描述 |
|---|---|
QTabWidget(QWidget *parent = nullptr) |
構(gòu)造函數(shù),創(chuàng)建一個(gè) QTabWidget 對(duì)象。 |
int addTab(QWidget *page, const QString &label) |
添加一個(gè)標(biāo)簽頁(yè),參數(shù) page 為標(biāo)簽頁(yè)的內(nèi)容,label 為標(biāo)簽頁(yè)的標(biāo)簽文本。返回新添加標(biāo)簽頁(yè)的索引。 |
void insertTab(int index, QWidget *page, const QString &label) |
在指定索引位置插入一個(gè)標(biāo)簽頁(yè)。 |
void removeTab(int index) |
移除指定索引位置的標(biāo)簽頁(yè)。 |
int currentIndex() const |
返回當(dāng)前活動(dòng)標(biāo)簽頁(yè)的索引。 |
void setCurrentIndex(int index) |
設(shè)置當(dāng)前活動(dòng)標(biāo)簽頁(yè)的索引。 |
QWidget *currentWidget() const |
返回當(dāng)前活動(dòng)標(biāo)簽頁(yè)的內(nèi)容窗口。 |
int count() const |
返回標(biāo)簽頁(yè)的總數(shù)。 |
QWidget *widget(int index) const |
返回指定索引位置的標(biāo)簽頁(yè)的內(nèi)容窗口。 |
QString tabText(int index) const |
返回指定索引位置的標(biāo)簽頁(yè)的標(biāo)簽文本。 |
void setTabText(int index, const QString &text) |
設(shè)置指定索引位置的標(biāo)簽頁(yè)的標(biāo)簽文本。 |
QIcon tabIcon(int index) const |
返回指定索引位置的標(biāo)簽頁(yè)的圖標(biāo)。 |
void setTabIcon(int index, const QIcon &icon) |
設(shè)置指定索引位置的標(biāo)簽頁(yè)的圖標(biāo)。 |
void clear() |
移除所有標(biāo)簽頁(yè)。 |
void setMovable(bool movable) |
設(shè)置標(biāo)簽頁(yè)是否可移動(dòng)。默認(rèn)為可移動(dòng)。 |
void setTabEnabled(int index, bool enable) |
設(shè)置指定索引位置的標(biāo)簽頁(yè)是否可用。 |
bool isTabEnabled(int index) const |
返回指定索引位置的標(biāo)簽頁(yè)是否可用。 |
int indexOf(QWidget *page) const |
返回指定內(nèi)容窗口所在的標(biāo)簽頁(yè)的索引。 |
QWidget *widget(const QString &label) const |
返回具有指定標(biāo)簽文本的標(biāo)簽頁(yè)的內(nèi)容窗口。 |
這些方法可以幫助你在 QTabWidget 中動(dòng)態(tài)地管理標(biāo)簽頁(yè),設(shè)置標(biāo)簽文本、圖標(biāo),以及進(jìn)行標(biāo)簽頁(yè)的切換和管理。
1.1 重復(fù)窗體分頁(yè)
重復(fù)窗體的使用廣泛應(yīng)用于標(biāo)簽頁(yè)克隆,例如一些遠(yuǎn)程SSH工具每次打開標(biāo)簽都是一個(gè)重復(fù)的交互環(huán)境,唯一不同的只是IP地址的變化,對(duì)于這些重復(fù)打開的標(biāo)簽頁(yè)面就可以使用此分頁(yè)來(lái)解決。
首先實(shí)現(xiàn)如下窗體布局,布局中空白部分是一個(gè)TabWidget分頁(yè)組件,下方是一個(gè)PushButton按鈕,當(dāng)用戶點(diǎn)擊按鈕時(shí),自動(dòng)將Dialog窗體追加到TabWidget組件中,如下圖;

首先讀者需要新建一個(gè)名叫FormDoc.ui的標(biāo)準(zhǔn)對(duì)話框,并在FormDoc構(gòu)造函數(shù)中對(duì)該窗體進(jìn)行初始化,如下代碼則是自定義 FormDoc 類的實(shí)現(xiàn),該類繼承自 QWidget。在構(gòu)造函數(shù)中,創(chuàng)建了垂直布局管理器 QVBoxLayout,并設(shè)置了一些邊距和間距。然后,通過 setLayout 將這個(gè)布局管理器應(yīng)用到 FormDoc 類的對(duì)象上。
在構(gòu)造函數(shù)中,通過 parentWidget() 獲取了父窗口指針,并通過強(qiáng)制類型轉(zhuǎn)換將其轉(zhuǎn)為 MainWindow* 類型。接著,通過調(diào)用 GetTableNumber() 方法獲取了選中標(biāo)簽的索引,然后將其輸出到控制臺(tái)。此處的GetTableNumber()是父類中的函數(shù),主要用于返回當(dāng)前TabWidget組件的下標(biāo)。
#include "formdoc.h"
#include "ui_formdoc.h"
#include "mainwindow.h"
#include <QVBoxLayout>
#include <iostream>
FormDoc::FormDoc(QWidget *parent) :QWidget(parent),ui(new Ui::FormDoc)
{
ui->setupUi(this);
QVBoxLayout *Layout = new QVBoxLayout();
Layout->setContentsMargins(2,2,2,2);
Layout->setSpacing(2);
this->setLayout(Layout);
// 獲取父窗口指針
MainWindow *parWind = (MainWindow*)parentWidget();
// 獲取選中標(biāo)簽索引
QString ref = parWind->GetTableNumber();
std::cout << ref.toStdString().data() << std::endl;
}
FormDoc::~FormDoc()
{
delete ui;
}
接著來(lái)看下MainWindow主窗體中是如何實(shí)現(xiàn)創(chuàng)建窗體的,當(dāng)用戶點(diǎn)擊PushButton按鈕時(shí),首先new FormDoc新建一個(gè)空的窗體,并通過 addTab 方法將 FormDoc 實(shí)例添加到 QTabWidget 中,設(shè)置了選項(xiàng)卡的顯示文本為 IP 地址("192.168.1.x")以及對(duì)應(yīng)的圖標(biāo)。然后,通過 setCurrentIndex 將新建的選項(xiàng)卡設(shè)置為當(dāng)前選中,并通過 setVisible(true) 確保 QTabWidget 是可見的。
另外,該主窗口還實(shí)現(xiàn)了一個(gè)槽函數(shù) on_tabWidget_tabCloseRequested,當(dāng)某個(gè)選項(xiàng)卡被關(guān)閉時(shí)觸發(fā)。在這個(gè)槽函數(shù)中,首先獲取被關(guān)閉的選項(xiàng)卡對(duì)應(yīng)的 QWidget 指針,然后調(diào)用 close 方法關(guān)閉選項(xiàng)卡。需要注意的是,如果在關(guān)閉選項(xiàng)卡時(shí)需要執(zhí)行一些清理工作,可以在 FormDoc 類的析構(gòu)函數(shù)中進(jìn)行相應(yīng)的處理。
void MainWindow::on_pushButton_clicked()
{
// 新建選項(xiàng)卡
FormDoc *ptr = new FormDoc(this);
// 關(guān)閉時(shí)自動(dòng)銷毀
ptr->setAttribute(Qt::WA_DeleteOnClose);
int cur = ui->tabWidget->addTab(ptr,QString::asprintf(" 192.168.1.%d",ui->tabWidget->count()));
ui->tabWidget->setTabIcon(cur,QIcon(":/image/1.ico"));
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
// 關(guān)閉Tab時(shí)執(zhí)行
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
if (index<0)
return;
QWidget* aForm=ui->tabWidget->widget(index);
aForm->close();
}
程序運(yùn)行后讀者可以點(diǎn)擊創(chuàng)建窗體按鈕,每次點(diǎn)擊都會(huì)創(chuàng)建一個(gè)獨(dú)立的新窗體,如下圖所示;

1.2 獨(dú)立窗體分頁(yè)
在1.1節(jié)中,筆者所介紹的方法僅用于重復(fù)功能頁(yè)面的創(chuàng)建,而有時(shí)我們需要讓不同的窗口展示不同的功能,此時(shí)就需要實(shí)現(xiàn)多窗體,通過ToolBar與TabWidget組件的配合可以很好的實(shí)現(xiàn)多窗體的應(yīng)用,如下圖通過ToolBar配置一個(gè)按鈕組件并初始化圖標(biāo)。

接著對(duì)窗體中的菜單欄依次綁定一個(gè)名稱,其中名稱使用action開頭,如下圖所示;

接著我們分別創(chuàng)建三個(gè)與之對(duì)應(yīng)的Dialog對(duì)話框,其中actionMain對(duì)應(yīng)formmain.ui、actionOption對(duì)應(yīng)到formoption.ui、actionCharts對(duì)應(yīng)到formcharts.ui上面,當(dāng)首頁(yè)按鈕被點(diǎn)擊后,在MainWindow中執(zhí)行如下操作,首先判斷窗體是否打開了,如果打開了則不允許繼續(xù)打開新的,而如果沒有被打開,那么我們就新建一個(gè)窗口,并設(shè)置到TabWidget上面,其代碼如下所示;
// 首頁(yè)菜單創(chuàng)建
void MainWindow::on_actionMain_triggered()
{
int tab_count = ui->tabWidget->count();
int option_count = 0;
for(int x=0; x < tab_count; x++)
{
// 獲取出每個(gè)菜單的標(biāo)題
QString tab_name = ui->tabWidget->tabText(x);
if(tab_name == "首頁(yè)菜單")
option_count = option_count + 1;
}
if(option_count < 1)
{
FormMain *ptr = new FormMain(this); // 新建選項(xiàng)卡
ptr->setAttribute(Qt::WA_DeleteOnClose); // 關(guān)閉時(shí)自動(dòng)銷毀
int cur=ui->tabWidget->addTab(ptr,QString::asprintf("首頁(yè)菜單"));
ui->tabWidget->setTabIcon(cur,QIcon(":/image/1.ico"));
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
}
系統(tǒng)設(shè)置頁(yè)面同理,這里我們規(guī)定系統(tǒng)設(shè)置頁(yè)面也只能打開一個(gè),其代碼如下所示;
// 創(chuàng)建系統(tǒng)設(shè)置菜單
void MainWindow::on_actionOption_triggered()
{
int tab_count = ui->tabWidget->count();
int option_count = 0;
for(int x=0; x < tab_count; x++)
{
// 獲取出每個(gè)菜單的標(biāo)題
QString tab_name = ui->tabWidget->tabText(x);
if(tab_name == "系統(tǒng)設(shè)置")
option_count = option_count + 1;
}
// 判斷首頁(yè)菜單是否只有一個(gè),可判斷標(biāo)簽個(gè)數(shù)來(lái)識(shí)別
if(option_count < 1)
{
FormOption *ptr = new FormOption(this);
ptr->setAttribute(Qt::WA_DeleteOnClose);
int cur = ui->tabWidget->addTab(ptr,QString::asprintf("系統(tǒng)設(shè)置"));
ui->tabWidget->setTabIcon(cur,QIcon(":/image/2.ico"));
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
}
最后一個(gè)是圖形繪制按鈕,該按鈕我們讓其可以彈出多個(gè),此處就不再限制彈出數(shù)量,只要點(diǎn)擊按鈕就新建一個(gè)并追加到TabWidget中,代碼如下所示;
// 繪圖頁(yè)面的彈出
void MainWindow::on_actionCharts_triggered()
{
FormCharts *ptr = new FormCharts(this);
ptr->setAttribute(Qt::WA_DeleteOnClose);
int cur = ui->tabWidget->addTab(ptr,QString::asprintf("圖形繪制"));
ui->tabWidget->setTabIcon(cur,QIcon(":/image/3.ico"));
ui->tabWidget->setCurrentIndex(cur);
ui->tabWidget->setVisible(true);
}
運(yùn)行后讀者可依次點(diǎn)擊不同的按鈕實(shí)現(xiàn)子窗體的創(chuàng)建,如下圖所示;

附件下載
本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請(qǐng)注明出處!

浙公網(wǎng)安備 33010602011771號(hào)