Qt——自定义界面之QStyle
1. Qt控件结构简介
首先我们要来讲讲GUI控件结构,这里以QComboBox为例:


一个完整的控件由一种或多种GUI元素构成:
- Complex Control Element。
- Primitive Element。
- Control Element。
1.1 Complex Control Element
Complex control elements contain sub controls. Complex controls behave differently depending on where the user handles them with the mouse and which keyboard keys are pressed.
Complex Control Elements(简称CC)包含子控件。根据用户对鼠标和键盘的不同处理,CC控件的表现也不同。上图中的QComboBox仅包含一个CC控件CC_ComboBox,该复杂控件又包含三个子控件(SC,Sub Control)SC_ComboBoxFrame、SC_ComboBoxArrow、SC_ComboBoxEditField。
1.2 Control Element
A control element performs an action or displays information to the user.
控件元素与用户交互相关,例如PushButton、CheckBox等等。QComboBox只有一个CE_ComboBoxLabel用以在ComboBox左侧展示当前选中或者正在编辑的文字。
1.3 Primitive Element
Primitive elements are GUI elements that are common and often used by several widgets.
主元素代表那些公共的GUI元素,主要用于GUI控件复用。例如PE_FrameFocusRect这个主元素就进场被多种控件用来绘制输入焦点。QComboBox包含两个主元素PE_IndicatorArrowDown、PE_FrameFocusRect。
2. QStyle、QProxyStyle、QStyleFactory简介
QStyle是一套抽象接口,它定义了实现界面控件外观的一系列api并且不能用来被实例化:
- virtual void drawComplexControl(...) 绘制复杂元素。
- virtual void drawControl(...) 绘制控件元素。
- virtual void drawPrimitive(...) 绘制主元素。
- ...
- virtual QSize sizeFromContent(...) 获取控件大小。
- virtual QRect subControlRect(...) 获取子控件位置及大小。
- virtual QRect subElementRect(...) 获取子元素位置及大小。
QProxyStyle实现了QStyle所有的抽象接口,并且默认保持系统风格,在Linux、Windows、Mac系统上样式如下:

QStyleFactory类提供了当前可应用的所有QStyle风格实现,在Windows系统上我获得如下几种风格(具体结果见最后一小节):
- Windows
- WindowsXp
- WindowsVista
- Fusion
我们可以通过QStyleFactory::keys()和QStyleFactory::create()来获取这些可用的风格并且设置到需要的QWidget上用以改变GUI风格。
3. 自定义QComboBox Style
这里我们通过实现一个QStyle来自定义QComboBox的样式。
这个自定义的QComboBox样式分为两部分,箭头区域和非箭头区域。非箭头区域包含CE_ComboBoxLabel和SC_CombBoxListBoxPopup。由于QStyle不负责绘制下拉框(由delegate绘制),我们只能更改下拉框的位置和大小(这里我们不做改变)。 箭头区域包含背景区和PE_IndicatorArrowDown。
箭头区域我们用一个辐射渐变来绘制背景,并且在鼠标Hover或者按下的时候更改渐变的颜色来重绘,中间的下拉箭头我们复用QProxyStyle的实现来完成。
void CustomeStyle::drawArrowArea(const QStyleOptionComplex *option,QPainter *painter,const QWidget *widget) const
{QRect arrowBoxRect = option->rect;arrowBoxRect.adjust(option->rect.width() * 0.8, 0, 0, 0);auto arrowAreaColor = Qt::darkCyan;m_arrowAreaHovered = arrowBoxRect.contains(widget->mapFromGlobal(QCursor::pos()));if (option->state & State_MouseOver && m_arrowAreaHovered)arrowAreaColor = Qt::cyan;else if (option->state & State_On && m_arrowAreaHovered)arrowAreaColor = Qt::darkMagenta;QRadialGradient gradient(arrowBoxRect.center(),arrowBoxRect.width());gradient.setColorAt(1.0, arrowAreaColor);painter->fillRect(arrowBoxRect, QBrush(gradient));auto arrowDownOption = *option;auto adjustPixel = arrowBoxRect.width() * 0.2;arrowDownOption.rect = arrowBoxRect.adjusted(adjustPixel,adjustPixel,-adjustPixel,-adjustPixel);drawPrimitive(PE_IndicatorArrowDown, &arrowDownOption, painter, widget);
}
非肩头区域即CE_ComboBoxLabel,我们用4种颜色的线性渐变来绘制,同箭头区域一样她也会根据当前的状态更改渐变颜色来增加交互效果:
auto comboBoxOption = qstyleoption_cast<const QStyleOptionComboBox*>(option);
if (comboBoxOption == nullptr)return;QColor gradientColors[] = {Qt::yellow,Qt::green,Qt::blue,Qt::red
};
QColor penColor = Qt::white;
if (option->state & State_MouseOver && !m_arrowAreaHovered) {for (auto& color : gradientColors)color.setAlpha(80);penColor.setAlpha(80);
} else if (option->state & State_On && !m_arrowAreaHovered) {for (auto& color : gradientColors)color = color.darker(300);penColor = penColor.darker(300);
}QRect labelRect = comboBoxOption->rect;
labelRect.adjust(0, 0, -(labelRect.width() * 0.2), 0);QLinearGradient linearGradient(labelRect.topLeft(), labelRect.bottomRight());
for (int i = 0; i < 4; ++i) {linearGradient.setColorAt(0.25 *i, gradientColors[i]);
}painter->fillRect(labelRect, QBrush(linearGradient));painter->setPen(QPen(penColor));
painter->drawText(labelRect, comboBoxOption->currentText, QTextOption(Qt::AlignCenter));
4. 实现效果






完整代码见链接。
5. 总结
QStyle优点:
- 统一风格。特定类型的控件效果都统一,如果要多处用到同一种类型的控件,用QStyle会比较方便。
QStyle缺点:
- 实现涉及Qt GUI控件结构细节,涉及知识面太多太杂。
- 只有Qt控件使用了QStyle,系统及第三方实现的控件不保证有效。
- 实现起来太复杂,不如重写QWidget的paintEvent配合其他事件来实现灵活。
相关文章:
Qt——自定义界面之QStyle
1. Qt控件结构简介 首先我们要来讲讲GUI控件结构,这里以QComboBox为例: 一个完整的控件由一种或多种GUI元素构成: Complex Control Element。Primitive Element。Control Element。 1.1 Complex Control Element Complex control elements …...
指针和数组面试题(逐题分析,完善你可能遗漏的知识)
人生不是一种享乐,而是一桩十分沉重的工作。 —— 列夫托尔斯泰 前言:之前我们就学习了数组和指针的知识。 数组:数组就是能够存放一组相同类型的元素,数组的大小取决于数组的元素个数和元素类型。 指针:…...
centos7搭建nfs挂载日志目录完整步骤
NFS服务器配置 1.安装NFS服务 首先使用yum安装nfs服务: yum -y install rpcbind nfs-utils 2.创建共享目录 在服务器上创建共享目录,并设置权限。 mkdir /data/share/ chmod 755 -R /data/share/ 3.配置NFS nfs的配置文件是 /etc/exports &…...
三、JavaScript
目录 一、JavaScript和html代码的结合方式 二、javascript和java的区别 1、变量 2、运算 3、数组(重点) 4、函数 5、重载 6、隐形参数arguments 7、js中的自定义对象 三、js中的事件 四、DOM模型 五、正则表达式 一、JavaScript和html代码的结合方…...
深圳大学计软《面向对象的程序设计》实验11 多继承
A. 在职研究生(多重继承) 题目描述 1、建立如下的类继承结构: 1)定义一个人员类CPeople,其属性(保护类型)有:姓名、性别、年龄; 2)从CPeople类派生出学生类CStudent,…...
并发变成实战-原子变量与非阻塞同步机制
文章目录1.锁的劣势2.硬件对并发的支持2.1 比较并交换2.2 非阻塞的计数器3.原子变量类3.1 原子变量是一种“更好的volatile”3.2 性能比较:锁与原子变量4.非阻塞算法4.1 非阻塞的栈4.2 非阻塞的链表4.3 ABA问题非阻塞算法设计和实现上要复杂的多,但在可伸…...
sql数据库常用操作指令
一、操作库-- 创建库create database db1;-- 创建库是否存在,不存在则创建create database if not exists db1;-- 查看所有数据库show databases;-- 查看某个数据库的定义信息 show create database db1; -- 修改数据库字符信息alter database db1 character set ut…...
4-1 定时任务的示例10个
文章目录前言基本命令与格式示例前言 Linux crontab 是用来定期执行程序的命令。当安装完成操作系统之后,默认都已经安装,并启动此任务调度命令。 crond 命令每分钟会定期检查是否有要执行的工作,如果有要执行的工作便会自动执行该工作。 基…...
外贸建站多少钱才能达到预期效果?
外贸建站多少钱才能达到预期效果?这是每个外贸企业都会问的问题。作为一个做外贸建站多年的人,我有一些个人的操盘感想。 首先,我认为外贸建站的投资是非常必要的。 因为在现代社会,网站已经成为外贸企业开展业务的必要工具之一…...
【Java学习笔记】5.Java 基本数据类型
Java 基本数据类型 变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。 内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。 因此,通过定义不同类型的变量…...
InnoDB 死锁和问题排查
文章目录死锁(dead lock)示例 1问题排查查看连接的线程查看相关的表查看最近一次的死锁信息查看服务器的锁信息查看正在使用的表如何尽可能地避免死锁死锁(dead lock) 两个及以上的事务各自持有对方需要的锁,导致双方…...
tensorflow07——使用tf.keras搭建神经网络(Sequential顺序神经网络)——六步法——鸢尾花数据集分类
使用tf.keras搭建顺序神经网络 六步法——鸢尾花数据集分类 01 导入相关包 02 导入数据集,打乱顺序 03 建立Sequential模型 04 编译——确定优化器,损失函数,评测指标(用哪一种准确率) 05 训练模型——把各项参入填入…...
关于Java连接Hive,Spark等服务的Kerberos工具类封装
关于Java连接Hive,Spark等服务的Kerberos工具类封装 idea连接服务器的hive等相关服务的kerberos认证注意事项 idea 本地配置,连接服务器;进行kerberos认证,连接hive、HDFS、Spark等服务注意事项: 本地idea连接Hadoo…...
大数据框架之Hadoop:MapReduce(五)Yarn资源调度器
Apache YARN (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统。用户可以将各种服务框架部署在 YARN 上,由 YARN 进行统一地管理和资源分配。 简言之,Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源&…...
uniapp实现地图点聚合功能
前言 在工作中接到的一个任务,在app端实现如下功能: 地图点聚合地图页面支持tab切换(设备、劳务、人员)支持人员搜索显示分布 但是uniapp原有的map标签不支持点聚合功能(最新的版本支持了点聚合功能)&am…...
经典分类模型回顾2—GoogleNet实现图像分类(matlab版)
GoogleNet是深度学习领域的一种经典的卷积神经网络,其在ImageNet图像分类任务上的表现十分优秀。下面是使用Matlab实现GoogleNet的图像分类示例。 1. 数据准备 在开始之前,需要准备一些图像数据用来训练和测试模型,可以从ImageNet等数据集中…...
Java经典面试题——谈谈 final、finally、finalize 有什么不同?
典型回答 final 可以用来修饰类、方法、变量,分别有不同的意义,final 修饰的 class 代表不可以继承扩展, final 的变量是不可以修改的,而 final 的方法也是不可以重写的(override)。 finally 则是 Java 保…...
C#的Version类型值与SQL Server中二进制binary类型转换
使用C#语言编写的应用程序可以通过.NET Framework框架提供的Version类来控制每次发布的版本号,以便更好控制每次版本更新迭代。 版本号由两到四个组件组成:主要、次要、内部版本和修订。 版本号的格式如下所示, 可选组件显示在方括号 ([ 和…...
软测入门(五)接口测试Postman
Postman 一款Http接口收工测试工具。如果做自动化测试会使用jemter做。 安装 去官网下载即可。 https://www.postman.com/downloads/?utm_sourcepostman-home 功能介绍 页面上的单词基本上都能了解,不多介绍。 转代码&注释 可将接口的访问转为其他语言的…...
UWB通道选择、信号阻挡和反射对UWB定位范围和定位精度的影响
(一)介绍检查NLOS操作时需要考虑三个方面:(1)由于整体信号衰减,通信范围减小。(2)由于直接路径信号的衰减,导致直接路径检测范围的减小。(3)由于阻…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)
Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习) 一、Aspose.PDF 简介二、说明(⚠️仅供学习与研究使用)三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...
React从基础入门到高级实战:React 实战项目 - 项目五:微前端与模块化架构
React 实战项目:微前端与模块化架构 欢迎来到 React 开发教程专栏 的第 30 篇!在前 29 篇文章中,我们从 React 的基础概念逐步深入到高级技巧,涵盖了组件设计、状态管理、路由配置、性能优化和企业级应用等核心内容。这一次&…...
PH热榜 | 2025-06-08
1. Thiings 标语:一套超过1900个免费AI生成的3D图标集合 介绍:Thiings是一个不断扩展的免费AI生成3D图标库,目前已有超过1900个图标。你可以按照主题浏览,生成自己的图标,或者下载整个图标集。所有图标都可以在个人或…...
简单介绍C++中 string与wstring
在C中,string和wstring是两种用于处理不同字符编码的字符串类型,分别基于char和wchar_t字符类型。以下是它们的详细说明和对比: 1. 基础定义 string 类型:std::string 字符类型:char(通常为8位)…...
python打卡day49@浙大疏锦行
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 一、通道注意力模块复习 & CBAM实现 import torch import torch.nn as nnclass CBAM(nn.Module):def __init__…...
