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节中,笔者所介绍的方法仅用于重复功能页面的创建,而有时我们需要让不同的窗口展示不同的功能,此时就需要实现多窗体,通过ToolBar与TabWidget组件的配合可以很好的实现多窗体的应用,如下图通过ToolBar配置一个按钮组件并初始化图标。

接着对窗体中的菜单栏依次绑定一个名称,其中名称使用action开头,如下图所示;

接着我们分别创建三个与之对应的Dialog对话框,其中actionMain对应formmain.ui、actionOption对应到formoption.ui、actionCharts对应到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);
}
运行后读者可依次点击不同的按钮实现子窗体的创建,如下图所示;

相关文章:
 
C++ Qt开发:TabWidget实现多窗体功能
Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TabWidget标签组件的常用方法及灵活运用。 Q…...
 
【轻量化篇】YOLOv8改进实战 | 更换主干网络 Backbone 之 RepGhostnet,重参数化实现硬件高效的Ghost模块
YOLOv8专栏导航:点击此处跳转 前言 轻量化网络设计是一种针对移动设备等资源受限环境的深度学习模型设计方法。下面是一些常见的轻量化网络设计方法: 网络剪枝:移除神经网络中冗余的连接和参数,以达到模型压缩和加速的目的。分组卷积:将卷积操作分解为若干个较小的卷积操…...
 
【STM32工具篇】使用CLion开发STM32
本文主要记录使用CLion开发STM32,并调试相关功能 使用的CLion版本:2023.3.1 CLion嵌入式配置教程:STM32CubeMX项目 |CLion 文档 (jetbrains.com) OpenOCD官网下载:Download OpenOCD for Windows (gnutoolchains.com) GNU ARM工…...
 
elementui中的el-table,当使用fixed属性时,table主体会遮挡住滚动条的大半部分,导致很难选中。
情况: 解决: el-table加个类,这里取为class"table" 然后是样式部分: <style scoped lang"scss"> ::v-deep.table {// 滚动条高度调整::-webkit-scrollbar {height: 15px;}// pointer-events 的基本信…...
 
鸿蒙端H5容器化建设——JSB通信机制建设
1. 背景 2023年鸿蒙开发者大会上,华为宣布为了应对国外技术封锁的潜在风险,2024年的HarmonyOS NEXT版本中将不再兼容Android,并推出鸿蒙系统以及其自研的开发框架,形成开发生态闭环。同时,在更高维度上华为希望将鸿蒙…...
 
数据管理平台Splunk Enterprise本地部署结合内网穿透实现远程访问
文章目录 前言1. 搭建Splunk Enterprise2. windows 安装 cpolar3. 创建Splunk Enterprise公网访问地址4. 远程访问Splunk Enterprise服务5. 固定远程地址 前言 Splunk Enterprise是一个强大的机器数据管理平台,可帮助客户分析和搜索数据,以及可视化数据…...
 
MaBatis使用`ResultMap`标签手动映射详解使用
文章目录 MaBatis使用ResultMap标签手动映射详解使用1、MyBatis只能自动维护库表”列名“与”属性名“相同时的对应关系,二者不同时无法自动ORM,如下:2、在SQL中使用 as 为查询字段添加列别名,以匹配属性名:但是如果我…...
openstack-keystone服务
文章目录 keystone服务安装和配置先决条件安装并配置组件运行以下命令来安装包。编辑文件 /etc/keystone/keystone.conf 并完成如下动作:初始化身份认证服务的数据库:初始化Fernet keys:Bootstrap the Identity service: 配置 Apache HTTP 服…...
 
大数据HCIE成神之路之数据预处理(3)——数值离散化
数值离散化 1.1 无监督连续变量的离散化 – 聚类划分1.1.1 实验任务1.1.1.1 实验背景1.1.1.2 实验目标1.1.1.3 实验数据解析 1.1.2 实验思路1.1.3 实验操作步骤1.1.4 结果验证 1.2 无监督连续变量的离散化 – 等宽划分1.2.1 实验任务1.2.1.1 实验背景1.2.1.2 实验目标1.2.1.3 实…...
 
stm32 寄存器、地址、位带操作
存储器区域功能划分 4GB 的地址空间中,ARM 已经粗线条的平均分成了 8 个块,每块 512MB,每个块也都规定了用途,具体分类见表格 6-1。每个块的大小都有 512MB,显然这是非常大的,芯片厂商在每个块的范围内设计…...
 
记录 | gdb使用backward-cpp来美化调试log
# 在当前工程目录下 git clone https://github.com/bombela/backward-cpp.git 编辑CMakeList.txt cmake_minimum_required(VERSION 3.15)project(exampleproj LANGUAGES CXX)add_subdirectory(backward-cpp)add_executable(main main.cpp)target_sources(main PUBLIC ${BACKW…...
 
EasyExcel模板导出(行和列自动合并)
1.需求背景: ①需要从第三方获取数据,第三方接口有两个参数,开始时间和结束时间 ②获取回来的数据并没有入库,所以不能通过数据库将数据归类统计,excel合并大概的流程是判断上一行或者左右相邻列是否相同,然后进行合并,所以不能是零散的数据且客户要求每一个自治区和每一个航站…...
 
EOCR-i3MZ/iFMZ施耐德漏电保护继电器产品简介
EOCR-i3MZ/iFMZ是施耐德EOCR的新一代电子式电动机保护器产品,具有过电流、欠电流、缺相、逆相、堵转、失速、三相不平衡、接地等保护功能。EOCR-i3MZ/iFMZ是通讯型产品,提供Modbus RTU通讯协议,RS485接口。 为方便设备维护人员排查电动机的故…...
golang开发--beego入门
Beego 是一个基于 Go 语言的开源框架,用于构建 Web 应用程序和 API。它采用了一些常见的设计模式,以提高开发效率、代码可维护性和可扩展性。 一,MVC设计模式 Beego 框架采用了经典的 MVC(Model-View-Controller)设计…...
 
python调取一欧易API并写一个比特币均线交易策略
比特币均线交易策略是一种基于比特币价格的移动均线的交易策略。它通过计算不同时间段的移动均线来确定买入和卖出点。 具体步骤如下: 确定要使用的均线。常用的均线包括5日、10日、20日、50日和200日均线。较短的均线可以更快地反应价格变动,而较长的均…...
使用arthas排查请求超时问题
现象 客户端调用服务时间出现偶尔超时现象 排查 因为服务已开启arthas,使用trace命令监控 $ trace com.lizz slowfun #cost > 1000 -n 10 监控com.lizz类中的slowfun方法,输出用时超过1000ms的记录,记录10条 Press CtrlC to abort. Aff…...
SAP ABAP EXCEL 下载模板并导入
具体参考: ABAP EXCEL 下载摸板 获取数据模板文件路径 FORM fm_get_filepath .DATA: lv_filename TYPE string,lv_path TYPE string,lv_fullpath TYPE string,lv_title TYPE string.co_objid ZMMRP002.CONCATENATE co_objid - sy-datum sy-uzeit INTO l…...
 
Map集合体系
Map集合的概述 Map集合是一种双列集合,每个元素包含两个数据。 Map集合的每个元素的格式:keyvalue(键值对元素)。 Map集合也被称为“键值对集合”。 Map集合的完整格式:{key1value1 , key2value2 , key3value3 , ...} Map集合的使用场景…...
 
速度与稳定性的完美结合:深入横测ToDesk、TeamViewer和AnyDesk
文章目录 前言什么是远程办公?远程办公的优势 远程办公软件横测对象远程软件的注册&安装ToDeskTeamViewerAnyDesk 各场景下的实操体验1.办公文件传输及丢包率2.玩游戏操作延迟、稳定3.追剧画质流畅度、稳定4.临时技术支持SOS模式 收费情况与设备连接数总结 前言…...
 
数据库系统的结构
数据库系统的结构 1 数据抽象1.1 物理层1.2 逻辑层1.3 视图层 2 实例和模式3 数据独立性4 数据模型4.1 基于对象的逻辑模型4.2 基于记录的逻辑模型4.3 基于记录的物理模型 5 数据库语言5.1 数据定义语言 DDL5.2 数据操纵语言 DML 6 事务7 存储管理器8 数据库系统的总体结构 1 数…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
 
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
 
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
 
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
 
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
 
从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...
