C++ Qt開發:TabWidget實現多窗體功能

lyshark發表於2023-12-20

Qt 是一個跨平臺C++圖形介面開發庫,利用Qt可以快速開發跨平臺窗體應用程式,在Qt中我們可以透過拖拽的方式將不同元件放到指定的位置,實現圖形化開發極大的方便了開發效率,本章將重點介紹TabWidget標籤元件的常用方法及靈活運用。

QTabWidget 是Qt中用於實現標籤頁(tabbed interface)的控制元件,可以在一個視窗內切換不同的頁面。在開發窗體應用時通常會伴隨功能的分頁,使用TabWidget並配合自定義Dialog元件,即可實現一個複雜的多窗體分頁結構,此類佈局方式也是多數軟體通用的方案。

以下是 QTabWidget 的一些常用方法,以表格形式概述:

方法簽名 描述
QTabWidget(QWidget *parent = nullptr) 建構函式,建立一個 QTabWidget 物件。
int addTab(QWidget *page, const QString &label) 新增一個標籤頁,引數 page 為標籤頁的內容,label 為標籤頁的標籤文字。返回新新增標籤頁的索引。
void insertTab(int index, QWidget *page, const QString &label) 在指定索引位置插入一個標籤頁。
void removeTab(int index) 移除指定索引位置的標籤頁。
int currentIndex() const 返回當前活動標籤頁的索引。
void setCurrentIndex(int index) 設定當前活動標籤頁的索引。
QWidget *currentWidget() const 返回當前活動標籤頁的內容視窗。
int count() const 返回標籤頁的總數。
QWidget *widget(int index) const 返回指定索引位置的標籤頁的內容視窗。
QString tabText(int index) const 返回指定索引位置的標籤頁的標籤文字。
void setTabText(int index, const QString &text) 設定指定索引位置的標籤頁的標籤文字。
QIcon tabIcon(int index) const 返回指定索引位置的標籤頁的圖示。
void setTabIcon(int index, const QIcon &icon) 設定指定索引位置的標籤頁的圖示。
void clear() 移除所有標籤頁。
void setMovable(bool movable) 設定標籤頁是否可移動。預設為可移動。
void setTabEnabled(int index, bool enable) 設定指定索引位置的標籤頁是否可用。
bool isTabEnabled(int index) const 返回指定索引位置的標籤頁是否可用。
int indexOf(QWidget *page) const 返回指定內容視窗所在的標籤頁的索引。
QWidget *widget(const QString &label) const 返回具有指定標籤文字的標籤頁的內容視窗。

這些方法可以幫助你在 QTabWidget 中動態地管理標籤頁,設定標籤文字、圖示,以及進行標籤頁的切換和管理。

1.1 重複窗體分頁

重複窗體的使用廣泛應用於標籤頁克隆,例如一些遠端SSH工具每次開啟標籤都是一個重複的互動環境,唯一不同的只是IP地址的變化,對於這些重複開啟的標籤頁面就可以使用此分頁來解決。

首先實現如下窗體佈局,佈局中空白部分是一個TabWidget分頁元件,下方是一個PushButton按鈕,當使用者點選按鈕時,自動將Dialog窗體追加到TabWidget元件中,如下圖;

首先讀者需要新建一個名叫FormDoc.ui的標準對話方塊,並在FormDoc建構函式中對該窗體進行初始化,如下程式碼則是自定義 FormDoc 類的實現,該類繼承自 QWidget。在建構函式中,建立了垂直佈局管理器 QVBoxLayout,並設定了一些邊距和間距。然後,透過 setLayout 將這個佈局管理器應用到 FormDoc 類的物件上。

在建構函式中,透過 parentWidget() 獲取了父視窗指標,並透過強制型別轉換將其轉為 MainWindow* 型別。接著,透過呼叫 GetTableNumber() 方法獲取了選中標籤的索引,然後將其輸出到控制檯。此處的GetTableNumber()是父類中的函式,主要用於返回當前TabWidget元件的下標。

#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();

    // 獲取選中標籤索引
    QString ref = parWind->GetTableNumber();
    std::cout << ref.toStdString().data() << std::endl;
}

FormDoc::~FormDoc()
{
    delete ui;
}

接著來看下MainWindow主窗體中是如何實現建立窗體的,當使用者點選PushButton按鈕時,首先new FormDoc新建一個空的窗體,並透過 addTab 方法將 FormDoc 例項新增到 QTabWidget 中,設定了選項卡的顯示文字為 IP 地址("192.168.1.x")以及對應的圖示。然後,透過 setCurrentIndex 將新建的選項卡設定為當前選中,並透過 setVisible(true) 確保 QTabWidget 是可見的。

另外,該主視窗還實現了一個槽函式 on_tabWidget_tabCloseRequested,當某個選項卡被關閉時觸發。在這個槽函式中,首先獲取被關閉的選項卡對應的 QWidget 指標,然後呼叫 close 方法關閉選項卡。需要注意的是,如果在關閉選項卡時需要執行一些清理工作,可以在 FormDoc 類的解構函式中進行相應的處理。

void MainWindow::on_pushButton_clicked()
{
    // 新建選項卡
    FormDoc *ptr = new FormDoc(this);

    // 關閉時自動銷燬
    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);
}

// 關閉Tab時執行
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
    if (index<0)
        return;
    QWidget* aForm=ui->tabWidget->widget(index);
    aForm->close();
}

程式執行後讀者可以點選建立窗體按鈕,每次點選都會建立一個獨立的新窗體,如下圖所示;

1.2 獨立窗體分頁

1.1節中,筆者所介紹的方法僅用於重複功能頁面的建立,而有時我們需要讓不同的視窗展示不同的功能,此時就需要實現多窗體,透過ToolBarTabWidget元件的配合可以很好的實現多窗體的應用,如下圖透過ToolBar配置一個按鈕元件並初始化圖示。

接著對窗體中的選單欄依次繫結一個名稱,其中名稱使用action開頭,如下圖所示;

接著我們分別建立三個與之對應的Dialog對話方塊,其中actionMain對應formmain.uiactionOption對應到formoption.uiactionCharts對應到formcharts.ui上面,當首頁按鈕被點選後,在MainWindow中執行如下操作,首先判斷窗體是否開啟了,如果開啟了則不允許繼續開啟新的,而如果沒有被開啟,那麼我們就新建一個視窗,並設定到TabWidget上面,其程式碼如下所示;

// 首頁選單建立
void MainWindow::on_actionMain_triggered()
{
    int tab_count = ui->tabWidget->count();
    int option_count = 0;

    for(int x=0; x < tab_count; x++)
    {
        // 獲取出每個選單的標題
        QString tab_name = ui->tabWidget->tabText(x);

        if(tab_name == "首頁選單")
            option_count = option_count + 1;
    }

    if(option_count < 1)
    {
        FormMain *ptr = new FormMain(this);              // 新建選項卡
        ptr->setAttribute(Qt::WA_DeleteOnClose);         // 關閉時自動銷燬

        int cur=ui->tabWidget->addTab(ptr,QString::asprintf("首頁選單"));
        ui->tabWidget->setTabIcon(cur,QIcon(":/image/1.ico"));

        ui->tabWidget->setCurrentIndex(cur);
        ui->tabWidget->setVisible(true);
    }
}

系統設定頁面同理,這裡我們規定系統設定頁面也只能開啟一個,其程式碼如下所示;

// 建立系統設定選單
void MainWindow::on_actionOption_triggered()
{
    int tab_count = ui->tabWidget->count();
    int option_count = 0;

    for(int x=0; x < tab_count; x++)
    {
        // 獲取出每個選單的標題
        QString tab_name = ui->tabWidget->tabText(x);

        if(tab_name == "系統設定")
            option_count = option_count + 1;
    }

    // 判斷首頁選單是否只有一個,可判斷標籤個數來識別
    if(option_count < 1)
    {
        FormOption *ptr = new FormOption(this);
        ptr->setAttribute(Qt::WA_DeleteOnClose);

        int cur = ui->tabWidget->addTab(ptr,QString::asprintf("系統設定"));
        ui->tabWidget->setTabIcon(cur,QIcon(":/image/2.ico"));

        ui->tabWidget->setCurrentIndex(cur);
        ui->tabWidget->setVisible(true);
    }
}

最後一個是圖形繪製按鈕,該按鈕我們讓其可以彈出多個,此處就不再限制彈出數量,只要點選按鈕就新建一個並追加到TabWidget中,程式碼如下所示;

// 繪圖頁面的彈出
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);
}

執行後讀者可依次點選不同的按鈕實現子窗體的建立,如下圖所示;

附件下載

TabWidget

相關文章