【QT入门】 无边框窗口设计之综合运用,实现WPS的tab页面

往期回顾:

【QT入门】 无边框窗口设计之实现窗口阴影-CSDN博客

【QT入门】 无边框窗口设计之实现圆角窗口-CSDN博客

【QT入门】 无边框窗口设计综合运用之自定义标题栏带圆角阴影的窗口-CSDN博客

 【QT入门】 无边框窗口设计之综合运用,实现WPS的tab页面

一、最终效果

 实现自增tab页面,不同tab页面之间的切换等,同时右键单击tab页面会弹出菜单栏

二、主界面类设计

主界面类,负责整合标题栏和下面的widget,整合很简单,创建一个tab类添加进来就ok

WPSDemo::WPSDemo(QWidget* parent): QWidget(parent)
{ui.setupUi(this);setWindowFlags(Qt::FramelessWindowHint);//设置为无边框窗口setStyleSheet("background-color:#E3E4E7");//设置背景颜色tabbrowser* pTab = new tabbrowser(this); QHBoxLayout* pHLay = new QHBoxLayout(this);pHLay->addWidget(pTab);pHLay->setContentsMargins(6, 6, 6, 6);setLayout(pHLay);connect(pTab, &tabbrowser::sig_close, this, &WPSDemo::on_close);
}

三、Tab类设计

 tab类负责创建tab,实现相关逻辑,重点还是在这里。主要是创建、删除tab标签,以及样式切换。还有就是单击右键显示菜单这几个点需要注意。

1、定义tab标签样式

首先,定义了两个字符串变量 qss0 和 qss1,分别存储了两种不同的 QSS 样式表,用于设置标签页的外观。当tab标签的数量超过一定范围时,会出现一个切换按钮,也就需要切换不同样式。

QString qss0 = "QTabBar::tab{ \font: 75 12pt Arial; \text-align:left; \width:184px; \height:32; \background:#FFFFFF; \border:2px solid #FFFFFF; \border-bottom-color:#FFFFFF; \border-top-left-radius:4px; \border-top-right-radius:4px; \padding:2px; \margin-top:0px; \margin-right:1px; \margin-left:1px;  \margin-bottom:0px;} \QTabBar::tab:selected{  \color:#333333; /*文字颜色*/  \background-color:#FFFFFF;} \QTabBar::tab:!selected{ \color:#B2B2B2; \border-color:#FFFFFF;} \QTabBar::scroller{width: 0px;}";
QString qss1 = "QTabBar::tab{ \font: 75 12pt Arial; \text-align:left; \width:184px; \height:32; \background:#FFFFFF; \border:2px solid #FFFFFF; \border-bottom-color:#FFFFFF; \border-top-left-radius:4px; \border-top-right-radius:4px; \padding:2px; \margin-top:0px; \margin-right:1px; \margin-left:1px;  \margin-bottom:0px;} \QTabBar::tab:selected{  \color:#333333; /*文字颜色*/  \background-color:#FFFFFF;} \QTabBar::tab:!selected{ \color:#B2B2B2; \border-color:#FFFFFF;} \QTabBar::scroller{width: 36px;}";

2、初始化标签页并设置属性

 在 tabbrowser 类的构造函数中,初始化一个标签页,并设置了一些标签页的属性,如滚动、可关闭、可移动等。然后调用了initTabWidget()函数初始化标签页部件,并设置了初始的标签页操作标志为 NORMAL。

tabbrowser::tabbrowser(QWidget* parent) :QTabWidget(parent)
{this->addTab(new QWidget, u8"稻壳");  //定义最开始的tabthis->setUsesScrollButtons(true);  //滚动鼠标可切换tabthis->setTabsClosable(true);       //显示tab右侧的关闭按钮this->setMovable(true);            //tab可移动位置initTabWidget(); //初始化tabsetTabBarFlag(NORMAL); this->setStyleSheet(qss0);connect(this, &QTabWidget::tabCloseRequested, this, &tabbrowser::on_closeTab);
}

这里我们一共定义了4种标签页操作标志:

        //tab操作标志enum TAB_FLAG{NEW, //新建标签页的操作标志CLOSE, //关闭标签页的操作标志NORMAL, //普通标签页的操作标志SPECIAL //特殊标签页的操作标志,比如当只剩下一个标签页时};

然后需要根据传入的标志值计算标签页的总宽度,并根据总宽度是否超过当前窗口宽度来切换不同的 QSS 样式表。 

3、创建和删除tab标签

1、创建tab标签

用一个 on_newTab() 函数来新建标签页,获取当前标签页数量并转换为字符串作为标题,然后添加新的标签页,并根据需要设置标签页为可关闭状态。

void tabbrowser::on_newTab()
{int nCount = count(); //获取当前标签页的数量。QString  title = QString::number(nCount); //将当前标签页数量转换为字符串。title = "Page" + title; //将标题设置为 "Page" 后接当前标签页数量的字符串// 这里写的有问题,应该是 insertTabthis->addTab(new QWidget, title); //检查标签页是否可关闭,如果不可关闭,则设置标签页为可关闭状态。if (!tabsClosable()){setTabsClosable(true);}setTabBarFlag(NEW);
}
2、删除tab标签

 用一个on_closeTab() 函数来关闭指定索引的标签页,删除对应的窗口部件,并根据剩余标签页数量设置标签栏的标志,当只剩下一个标签页时,将标签页设置为不可关闭状态。

//关闭指定索引的标签页,并根据情况设置标签栏的标志
void tabbrowser::on_closeTab(int index)
{//删除指定索引的标签页的对应窗口部件widget(index)->deleteLater();setTabBarFlag(CLOSE); //设置标签栏的标志为 CLOSE//当只剩下1个tab时if (count() == 1){setTabsClosable(false); //设置标签页为不可关闭状态setTabBarFlag(SPECIAL); //设置标签栏的标志为 SPECIAL}
}

参考一下删除一个tab是怎么做的,是根据鼠标点击获取的index来delete,基于删除一个tab标签的操作,那么删除整个标签栏的操作自然也就很简单。我直接for循环delete所有,只剩下初始的那一个即可。

void tabbrowser::on_closeAllTab()
{for (int i = count(); i > 0; i--){//删除指定索引的标签页的对应窗口部件widget(i)->deleteLater();setTabBarFlag(CLOSE); //设置标签栏的标志为 CLOSE//当只剩下1个tab时if (count() == 1){setTabsClosable(false); //设置标签页为不可关闭状态setTabBarFlag(SPECIAL); //设置标签栏的标志为 SPECIAL}}
}

4、单击右键显示菜单

由于都是只创建菜单,大部分的具体实现都没做,所以还是很简单的,

//右键单击tab出现菜单栏
void tabbrowser::createTabMenu()
{m_pTabMenu = new QMenu(this);QAction* pAcSave = new QAction(QIcon(":/WPSDemo/resources/save.png"), u8"保存", m_pTabMenu);m_pTabMenu->addAction(pAcSave);connect(pAcSave, &QAction::triggered, [=] {QMessageBox::information(this, u8"提示", u8"你点击了 保存");}); //简单响应了一个保存的,其他的都还没做QAction* pAcSaveAs = new QAction(QString(u8"另存为"), m_pTabMenu);m_pTabMenu->addAction(pAcSaveAs);m_pTabMenu->addSeparator(); //这个是QAction之间的横线QAction* pAcShareDoc = new QAction(QIcon(":/WPSDemo/resources/share.png"), QString(u8"分享文档"), m_pTabMenu);m_pTabMenu->addAction(pAcShareDoc);QAction* pAcSendToDevice = new QAction(QString(u8"发送到设备"), m_pTabMenu);m_pTabMenu->addAction(pAcSendToDevice);m_pTabMenu->addSeparator();QAction* pAcNewName = new QAction(QString(u8"重命名"), m_pTabMenu);m_pTabMenu->addAction(pAcNewName);QAction* pAcSaveToWPSCloud = new QAction(QString(u8"保存到WPS云文档"), m_pTabMenu);m_pTabMenu->addAction(pAcSaveToWPSCloud);QAction* pAcCloseAll = new QAction(QString(u8"关闭所有文件"), m_pTabMenu);m_pTabMenu->addAction(pAcCloseAll);//删除所有和删除一个是差不多的connect(pAcCloseAll, &QAction::triggered, this, &tabbrowser::on_closeAllTab);
}

四、标题栏和tab标签的结合

负责标题栏右边的按钮实现,最后和tab结合,这个很简单的,看看代码,已经是很熟悉了,在这个类里不仅进行ui设计,还实现标题栏拖拽功能,绘图功能等。

#include "CTabTitleWidget.h"
#include <QHBoxLayout>
#include <QMouseEvent>
#include <QStyleOption>
#include <QPainter>#ifdef Q_OS_WIN
#include <qt_windows.h>
#pragma comment(lib, "user32.lib")
#endifCTabTitleWidget::CTabTitleWidget(QWidget* parent)
{setStyleSheet("background-color:#E3E4E7");m_pAddBtn = new QPushButton(this);m_pAddBtn->setFlat(true);m_pAddBtn->setFixedSize(32, 32);m_pAddBtn->setStyleSheet("background-image:url(:/WPSDemo/resources/add.svg)");m_pEmptyWidget = new QWidget(this);m_pUserBtn = new QPushButton(this);m_pUserBtn->setFlat(true);m_pUserBtn->setFixedSize(32, 32);m_pUserBtn->setStyleSheet("background-image:url(:/WPSDemo/resources/user)");m_pMinBtn = new QPushButton(this);m_pMinBtn->setFlat(true);m_pMinBtn->setFixedSize(32, 32);m_pMinBtn->setStyleSheet("background-image:url(:/WPSDemo/resources/min.svg)");m_pMaxBtn = new QPushButton(this);m_pMaxBtn->setFlat(true);m_pMaxBtn->setFixedSize(32, 32);m_pMaxBtn->setStyleSheet("background-image:url(:/WPSDemo/resources/max.svg)");m_pCloseBtn = new QPushButton(this);m_pCloseBtn->setFlat(true);m_pCloseBtn->setFixedSize(32, 32);m_pCloseBtn->setStyleSheet("background-image:url(:/WPSDemo/resources/close.svg)");QHBoxLayout* pHLay = new QHBoxLayout(this);pHLay->addWidget(m_pAddBtn);pHLay->addWidget(m_pEmptyWidget);this->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding);pHLay->addWidget(m_pUserBtn);pHLay->addSpacing(8);pHLay->addWidget(m_pMinBtn);pHLay->addWidget(m_pMaxBtn);pHLay->addWidget(m_pCloseBtn);pHLay->setContentsMargins(1, 0, 1, 3);setLayout(pHLay);connect(m_pAddBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_Clicked);connect(m_pMinBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_Clicked);connect(m_pMaxBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_Clicked);connect(m_pCloseBtn, &QPushButton::clicked, this, &CTabTitleWidget::on_Clicked);
}CTabTitleWidget::~CTabTitleWidget()
{
}void CTabTitleWidget::setEmptyWidgetWidth(int w)
{m_pEmptyWidget->setMinimumWidth(w);
}void CTabTitleWidget::paintEvent(QPaintEvent* event)
{QStyleOption opt;opt.init(this);QPainter p(this);style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);QWidget::paintEvent(event);
}void CTabTitleWidget::mousePressEvent(QMouseEvent* event)
{if (ReleaseCapture()){QWidget* pWindow = this->window();if (pWindow->isTopLevel()){SendMessage(HWND(pWindow->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);}}event->ignore();
}void CTabTitleWidget::mouseDoubleClickEvent(QMouseEvent* event)
{emit m_pMaxBtn->clicked();
}void CTabTitleWidget::on_Clicked()
{QPushButton* pButton = qobject_cast<QPushButton*>(sender());QWidget* pWindow = this->window();if (pWindow->isTopLevel()){if (pButton == m_pAddBtn){emit sig_addtab();}else if (pButton == m_pMinBtn){pWindow->showMinimized();}else if (pButton == m_pMaxBtn){pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();}else if (pButton == m_pCloseBtn){emit sig_close();}}
}

都看到这里了,点个赞再走呗朋友~

加油吧,预祝大家变得更强!

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

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

相关文章

Nexus的docker安装,maven私服

文章目录 前言安装创建文件夹设置文件夹权限docker创建指令制作docker-compose.yaml文件 查看网站访问网页查看密码 前言 nexus作为私服的maven仓库&#xff0c;在企业级应用中&#xff0c;提供了依赖来源的稳定性&#xff0c;为构建庞大的微服务体系&#xff0c;打下基础 安…

如何实现在不给定长度的情况下进行输入?

在输入一串数字时&#xff0c;不管是使用for循环还while循环&#xff0c;我们都必须知道要输入的具体长度。 可是如果题目没有给定输入长度&#xff0c;也没有给定最大范围呢&#xff1f; 同样也有for与while两种循环方式。 for #include<iostream> using namespace …

Svelte Web 框架介绍

Svelte 是一个用于构建网络应用程序的现代框架&#xff0c;它与其他用户界面框架&#xff08;如React和Vue&#xff09;有着本质的不同。Svelte 的核心理念是在构建应用程序时&#xff0c;将大部分工作转移到编译步骤中&#xff0c;而不是在用户的浏览器中运行时处理。这种方法…

算法——分治(快速排序)

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享分治算法关于快速排序的专题 对于快速排序在我个人主页专栏 <排序> 有详细的介绍,此专题对快排进行了优化操作,并介绍了优化后的快排的几种运用 如果有不足的或者错误的请…

Linux初学(十五)ssh服务

一、SSH服务 1.1 简介 远程登录Linux用的就是ssh服务 ssh服务的特点就是数据会机密传输 ssh服务 组件&#xff1a;openssl 服务名&#xff1a;sshd 默认端口&#xff1a;22 1.2 配置文件 /etc/ssh/sshd_config #Port 22 ssh的端口 #Use…

【正点原子探索者STM32F4】TFTLCD实验学习记录:FSMC控制 TFTLCD的寄存器配置

FSMC控制 TFTLCD的寄存器配置 异步模式 A控制 TFTLCDFSMC寄存器配置ILI9341电平持续时间要求 参考 异步模式 A控制 TFTLCD LCD以ILI9341为例 FSMC寄存器配置 对于异步突发访问方式&#xff0c; FSMC 主要设置 3 个时间参数&#xff1a;地址建立时间(ADDSET)、 数据 建立时间…

Linux服务器上安装多个版本cuda的一些准备

1. 在已经有cuda10.1的基础上安装cuda11.3并配置进环境变量 linux20.04 cuda避坑安装/nvidia驱动/环境配置/安装cuDNN_linux安装cuda-CSDN博客 2. 配置环境变量的过程需要用到Vim编辑器&#xff0c;Vim编辑器的使用方法 vim 的基本使用命令_vim命令行操作-CSDN博客 3.cuda…

Java学习之抽象类和接口

目录 抽象方法和抽象类 示例 使用要点 接口(interface) 作用 定义及使用 声明格式 定义接口的详细说明 要点 示例 接口中定义静态方法和默认方法(JDK8及以后) 默认方法 示例 静态方法 接口的多继承 示例 抽象方法和抽象类 抽象方法 使用abstract修饰的方法&…

Unity之PUN实现多人联机射击游戏的优化(Section 2)

目录 &#x1f3ae;一、准备工作 &#x1f3ae;二、实现手雷投掷动作 &#x1f3ae;三、手雷投掷同步 &#x1f4a4;3.1 photonView.RPC &#x1f3ae;四、同步手雷伤害 这几周都给我布置任务了&#xff0c;最近可忙。现在终于有机会更新了&#xff0c;也谢谢大家的阅读&a…

JavaSE-11笔记【多线程2(+2024新)】

文章目录 6.线程安全6.1 线程安全问题6.2 线程同步机制6.3 关于线程同步的面试题6.3.1 版本16.3.2 版本26.3.3 版本36.3.4 版本4 7.死锁7.1 多线程卖票问题 8.线程通信8.1 wait()和sleep的区别&#xff1f;8.2 两个线程交替输出8.3 三个线程交替输出8.4 线程通信-生产者和消费者…

C++枚举类型

在 C++ 中,枚举(Enumeration)是一种用户定义的数据类型,用于定义一组有限的命名常量。枚举类型可以简化代码,提高代码的可读性。 C++ 中的枚举类型有两种:普通枚举和枚举类。 1. 普通枚举 普通枚举使用关键字 enum 定义,可以指定枚举常量的取值。 #include <iost…

Tailwind 4.0 即将到来:前端开发的“速度与激情”

随着前端开发技术的不断进步&#xff0c;我们每天都在寻找更快、更简洁的解决方案来提升我们的开发效率和用户体验。今天&#xff0c;我要为大家介绍一项令人振奋的新技术进展——Tailwind 4.0的来临&#xff01; 对于经常使用Tailwind的朋友们来说&#xff0c;这个消息无疑是激…

阿里云短信服务业务

一、了解阿里云用户权限操作 1.注册账号、实名认证&#xff1b; 2.使用AccessKey 步骤一 点击头像&#xff0c;权限安全的AccessKey 步骤二 设置子用户AccessKey 步骤三 添加用户组和用户 步骤四 添加用户组记得绑定短信服务权限 步骤五 添加用户记得勾选openApi访问 添加…

Educational Codeforces Round 162 (Rated for Div. 2) ----- E. Count Paths --- 题解

E. Count Paths&#xff1a; 题目大意&#xff1a; 思路解析&#xff1a; 根据题目中定义的美丽路径&#xff0c;我们可以发现路径只有两种情况&#xff1a; 当前结点作为起始结点&#xff0c;那我们只需要知道它的子树下有多少个相同颜色的结点&#xff0c;并且相同颜色的结…

使用 HTMX 和 Bun 进行全栈 Web 开发

将 HTMX 放在前端&#xff0c;Bun 放在后端&#xff0c;然后将它们与 Elysia 和 MongoDB 连接起来&#xff0c;形成快速便捷的技术栈&#xff0c;使开发 Web 应用程序变得轻而易举。 Bun 和 HTMX 是目前软件领域最有趣的两个事情。 Bun 是一个速度极快的一体化服务器端 JavaSc…

如何创建一个TCP多人聊天室?

一、什么是TCP&#xff1f; TCP&#xff08;Transmission Control Protocol&#xff09;是一种可靠的 面向连接的协议 &#xff0c;可以保证数据在传输过程中不会丢失、重复或乱序。 利用TCP实现简单聊天程序&#xff0c;需要客户端和服务器端之间建立TCP连接&#xff0c;并通…

STC8H8K64U 学习笔记 - 位运算

STC8H8K64U 学习笔记 -位运算 环境说明引脚说明 位运算实例 环境说明 该内容仅针对我自己学习的开发板做的笔记&#xff0c;在实际开发中需要针对目标电路板的原理图进行针对性研究。 芯片&#xff1a;STC8H8K64U烧录软件&#xff1a;stc-isp-v6.92G编码工具&#xff1a;天问 …

蚂蚁退地,房价猛跌

蚂蚁退地&#xff0c;房价猛跌 2020年-2021年&#xff0c;蚂蚁集团先后拿下之江度假区钱塘江岸 XH1710-B1/B2-23 和 XH1708-02 地块。 一时间&#xff0c;"蚂蚁集团坐拥大量土地&#xff0c;欲打造全球总部"的消息传遍全国&#xff0c;之江板块房价连夜猛涨&#xff…

MATLAB近红外光谱分析技术应用

郁磊副教授&#xff0c;主要从事MATLAB编程、机器学习与数据挖掘、数据可视化和软件开发、生理系统建模与仿真、生物医学信号处理&#xff0c;具有丰富的实战应用经验&#xff0c;主编《MATLAB智能算法30个案例分析》、《MATLAB神经网络43个案例分析》相关著作。已发表多篇高水…

【Python语法实例】-12猜单词游戏

一、游戏背景与需求 猜单词游戏是一种经典的文字游戏,玩家需要通过提示的字母组合,猜出正确的单词。这个游戏不仅考验玩家的词汇量和推理能力,还能在娱乐中提升编程技能。我们的目标是创建一个简单易懂的猜单词游戏,让玩家在享受游戏乐趣的同时,也能感受到Python编程的实…