C++ Qt开发:TabWidget实现多窗体功能

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);
}

运行后读者可依次点击不同的按钮实现子窗体的创建,如下图所示;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237103.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MVVM响应式

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介MVVM响应式1. 什么是MVVM模式?2. Vue中的响应式数据3. 数据绑定与视图更新⭐ 写在最后⭐ 专栏简介 Vue学习之旅的奇妙世界 欢迎大家来到 Vue 技能树参考资料专栏!创建这个专栏的初衷是为了帮助大家更好地应对 Vue.js 技能树的学习…

NVIDIA GPU日志解读

目录 2023-12-20 21:39:14.437944: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations: AVX AVX2To …

IspSrver-DNS

2023年全国网络系统管理赛项真题 模块B-Windows解析 题目 安装DNS服务器,根据题目创建必要正向区域和反向区域的DNS解析。把当前机器作为互联网根域服务器,创建test1.com~test100.com,并在所有正向区域中创建一条A记录,解析到本机地址。配置步骤 安装DNS服务器,根据题目创…

eclipse部分常用快捷键的使用

eclipse部分常用快捷键的使用 注释部分 Ctrl / &#xff1a;注释或取消当前行注释。Ctrl Shift / &#xff1a;多行注释。Ctrl Shift \ &#xff1a;取消多行注释。AltShiftJ&#xff1a;方法注释。 代码部分 Alt /&#xff1a;代码提示补全。Ctrl 1&#xff1a;快速…

Copilot的实战经验分享和案例分析

案例一&#xff1a;快速开发REST API 在开发一个新的REST API时&#xff0c;Copilot可以大大加快开发速度。例如&#xff0c;当你需要创建一个新的用户端接口来添加新用户时&#xff0c;你可以在你的Python Flask应用中开始输入如下代码&#xff1a; app.route(/users, methods…

3842充电器电路图大全

3842充电器电路图&#xff08;一&#xff09; UC3842组成的充电器电路 图1中C1、V1&#xff5e;V4、C2组成滤波整流电路&#xff0c;变压器T为高频变压器&#xff0c;V5、R2、C11组成功率开关管V7的保护电路&#xff0c;NF为供给IC电源的绕组。单端输出IC为UC3842&#xff0c;…

Nacos-服务发现与配置管理v1.0

Nacos - 服务发现和配置管理 教学目标 1&#xff09;能够理解微服务架构的特点 2&#xff09;能够理解服务发现的流程 3&#xff09;能够说出Nacos的功能 4&#xff09;掌握Nacos的安装方法 5&#xff09;掌握RESTful服务发现开发方法 6&#xff09;掌握Dubbo服务发现开…

ICC2:Less than minimum edge length和Concave convex edge enclosure

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 首先,要介绍一下这两种drc Less than minimum edge length对应的tf rule如下: 而Concave convex edge enclosure对应图示和tf 规则如下,可

信息论安全与概率论

目录 一. Markov不等式 二. 选择引理 三. Chebyshev不等式 四. Chernov上限 4.1 变量大于 4.2 变量小于 信息论安全中会用到很多概率论相关的上界&#xff0c;本文章将梳理几个论文中常用的定理&#xff0c;重点关注如何理解这些定理以及怎么用。 一. Markov不等式 假定…

备忘:python和 java graphql client连Sky walking Server查询数据的联通性

本文仅做备忘 Skywalking OAP 关于graphql的url http://localhost:8090/graphql python3.10 需要安装 GraphQLClient库 testGraphQL.py程序 from graphqlclient import GraphQLClient import json if __name__ __main__:clientGraphQLClient(http://localhost:8090/graphql…

仙女麻麻看过来~你想要的穿搭我都有

精选优质匈牙利白鸭绒填充绒朵大而蓬松&#xff0c;毫无异味整件格充绒工艺不跑绒 更加的保暖舒适版型优秀显瘦不臃肿 黑色经典好穿又好看&#xff01;

获取请求体中json数据并解析到实体对象

目录 相关依赖 前端代码 后端代码 测试结果 相关依赖 <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version> </dependency> <dependency><groupId>comm…

在vue中,文件转base64示例

在Vue中&#xff0c;你可以使用FileReader对象将文件转换为Base64编码。以下是一个示例代码&#xff0c;演示了如何将文件转换为Base64编码&#xff1a; <template> <div> <input type"file" change"onFileChange"> <button clic…

【HarmonyOS开发】ArkUI实现下拉刷新/上拉加载

列表下拉刷新、上拉加载更多&#xff0c;不管在web时代还是鸿蒙应用都是一个非常常用的功能&#xff0c;基于ArkUI中TS扩展的声明式开发范式实现一个下拉刷新&#xff0c;上拉加载。 上拉加载、下拉刷新 如果数据量过大&#xff0c;可以使用LazyForEach代替ForEach 高阶组件-…

golang:Excel写入mysql数据库

要将读取的每个Sheet中的数据分别写入不同的MySQL数据库&#xff0c;你需要使用Go语言的MySQL数据库驱动&#xff0c;以及合适的数据库连接和插入逻辑。在Go中&#xff0c;可以使用github.com/go-sql-driver/mysql和github.com/jmoiron/sqlx等库来处理MySQL数据库连接和操作。 …

Seata1.4.2分布式事务搭建部署【Spring cloud Alibaba】

包下载 https://github.com/apache/incubator-seata/releases下载并上传到服务器 //解压 tar -zxvf seata-server-1.4.2.tar.gz创建Seata的数据库及表&#xff0c;地址&#xff1a;https://github.com/seata/seata/tree/develop/script/server 根据数据类型复制相应的sql&…

【 USRP安装教程】MATLAB 2023B

步骤 matlabdocusrp驱动包 doc 安装包内容列表 双击“R2023b_Doc_Windows.iso” 打开cmd 查看盘符 切换盘符 因为是F盘&#xff0c;所以cmd输入&#xff1a;“F:” F:进入可安装界面 cd F:\bin\win64安装离线文档库 .\mpm install-doc --matlabroot"C:\MATLAB\R202…

Java 第14章 集合 本章作业

文章目录 试分析HashSet和TreeSet分别如何实现去重的HashSet重复加入问题比较ArrayList和Vector 试分析HashSet和TreeSet分别如何实现去重的 (1) HashSet的去重机制&#xff1a;hashCode() equals()&#xff0c;底层先通过存入对象,进行运算得到一个hash值&#xff0c;通过ha…

scrapy_redis原理分析并实现断点续爬以及分布式爬虫

scrapy_redis原理分析并实现断点续爬以及分布式爬虫 学习目标 了解 scrapy实现去重的原理了解 scrapy中请求入队的条件掌握 scrapy_redis基于url地址的增量式单机爬虫掌握 scrapy_redis分布式爬虫 1. 下载github的demo代码 clone github scrapy-redis源码文件 git clone http…

node设置镜像源

node设置镜像源 设置镜像源 npm config set registry https://registry.npmmirror.com验证设置是否生效 检查当前的 npm 镜像源&#xff1a; npm config get registry镜像源设置到此结束&#xff0c;下面的为题外话 高版本node启动命令 package.json文件设置 set NODE_O…