Qt QWidget 独立窗口抗锯齿圆角的一个实现方案(支持子控件)

news2025/1/19 19:33:31

QWidget独立窗口抗锯齿圆角窗口的一个实现方案

由于 QWidget::setMask 接口设置圆角不支持抗锯齿,所以通常会使用透明窗口加圆角背景,但圆角背景不能满足对子控件的裁剪,子控件与圆角区域重叠的部分还是能显示出来。当然对于大多数窗口,留出足够的边距也是可以接受。

对一些特殊场景,比如QComboBox的列表框,UI设计师强烈要求圆角,列表与它的容器不能有边距,常规办法就很难做到。笔者在经过长时间的研究,有了一个可能的方案。

最终实现效果如下图,可以看到,列表项区域,滚动条区域也能够正常显示圆角。
抗锯齿圆角

注意,该方案可能不适用一些场景:

  1. 特殊的平台或Qt配置
  2. 复杂窗口且有性能要求
  3. 窗口尺寸较大(可以优化)
  4. 有嵌入式窗口、OpenGL、QWindow等

方案

基本原理

Qt的每个独立窗口,默认都是在一张图片上,层叠绘制所有子控件。通常我们自绘控件时,几乎不会使用QPainter::setCompositionMode设置其他混合模式,会出现比较奇怪的效果。但如果使用透明背景窗口,使用混合模式其实跟在QPixmap或QImage上绘制一样。

另外一点,当一个控件重绘时,由于底层的绘制会影响到上层透明合成,所以Qt会从下到上按顺序绘各个控件的脏区域。

所以理论上,如果在一个窗口上增加一个全尺寸的遮罩,重绘时使用混合模式就可以实现对一些像素的清除,且支持抗锯齿。

代码步骤

  1. 创建一个QWidget作为遮罩

    遮罩置于顶层,鼠标设置透传(WA_TransparentForMouseEvents)

    遮罩跟随窗口尺寸大小同步变化,保持一致。安装事件过滤器即可(installEventFilter)

  2. 重写paintEvent,利用混合模式清除圆角像素

    以下绘制逻辑比较直接,建议优化

	//创建一个图片,填充透明色
	QPixmap pix(this->size());
	pix.fill(QColor(0,0,0,0));
	// 在改图片上填充一个圆角区域,需要设置抗锯齿
	QPainter painter(&pix);
	painter.setRenderHint(QPainter::Antialiasing);
	QPainterPath path;
	//这里圆角区域需要根据dpi、size调整
	path.addRoundedRect(QRectF(pix.rect()).adjusted(0.5, 0.5, -0.5, -0.5), 10, 10); 
	painter.fillPath(path, Qt::white);
	painter.end();
	// 在窗口上绘制该圆角图片
	painter.begin(this);
	painter.setRenderHint(QPainter::Antialiasing);
	// 该混合模式会根据source像素的透明度,调整目标的透明度
	painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
	painter.drawPixmap(0, 0, pix);
	// 恢复默认混合模式,绘制边框,如果没有则不用
	painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
	painter.setPen(QPen(QColor(0xCA64EA), 1.0));
	painter.drawPath(path);

优化方向

  1. 性能优化

    上面的示例,使用了一整张图片对窗口像素进行混合模式的运算,且每次子控件重绘都会引起遮罩的重绘,性能比较差。可以考虑仅在四周设置圆角的遮罩。

  2. 圆角绘制优化

    本文使用了一个不透明的圆角区域对窗口设置裁剪,圆角的参数是固定在代码里的。实际QSS是可以设置窗口的圆角,因此可以借助QSS来生成一张圆角图片,就避免代码里包含固定数值。

    具体实现原理可以参考之前的文章,这里不具体展示了:
    QComboBox文字居中的一种解决办法
    Qt实现一个支持QSS的Switch Button
    Qt借助隐藏控件和QSS绘制重复元素

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

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

相关文章

使用Git和GitHub完成团队项目开发

前提 拥有自己的GitHub账号项目组组长已经创建好了 一个远程仓库能够科学上网安装了Git软件 基础步骤 该内容分为两个部分,分别为团队协作者(项目成员)和团队组织者(项目组长),我们首先来介绍作为项目成员…

BitoAI:新型AI编码助手,支持GPT-4

在之前的文章中,小编带大家分享体验过OpenAI的Cursor代码生成器、Codeium编程助手、亚马逊的CodeWhisperer。大家也都非常踊跃的在评论区分享了体验的感受及遇到的问题。 而最近又出现了一款新型编程助手BitoAI。今天的主要内容就是给大家介绍它,号称 I…

栈的顺序存储结构与操作 题目编号:457

题目描述 请你定义一个顺序栈,可以对顺序栈进行“将某个元素入栈”、“弹出栈顶元素”、“取栈顶元素(不删除)”、“判断栈是否为空”、“清空栈”等操作。键盘输入一些命令,可以执行上述操作。本题中,顺序栈元素为字…

宝塔面板主题模板修改详细使用教程

宝塔面板主题模板修改详细使用教程 宝塔面板目前没有完善的主题、语言包功能,因此资源均采用覆盖的方式使用。 使用前请确保面板版本与资源包版本一致,新版本没有资源可以使用 降级版本 的方式使用。 原创资源均采用只修改少量静态文件的方式&#xff0c…

Portainer自定义设置默认的用户名密码

文章目录 Portainer介绍用户密码问题解决一半未完待续 Portainer介绍 Portainer是一款轻量级的Docker管理Web界面,它可以让用户方便地管理和部署Docker容器,管理Docker Swarm集群等用户可以通过Portainer轻松完成基于Docker的应用部署、镜像管理、容器监…

三台Windows服务器搭建RabbitMq集群及镜像队列

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、RabbitMq是什么?二、RabbitMq集群搭建步骤1.环境说明2.RabbitMQ 安装3.RabbitMQ 集群搭建4.RabbitMQ镜像队列 总结 前言 消息中间件-RabbitMq集…

Ubuntu 23.04 安装 Harbor

Ubuntu 23.04 安装 Harbor 安装 Docker CE配置 tls 证书配置 docker 信任自签名证书下载和安装 Harbor设置 Harbor 开机启动验证 安装 Docker CE sudo apt-get remove docker docker-engine docker.io containerd runcsudo apt-get update -y sudo apt-get install -y \ca-cer…

shell脚本----循环语句for

文章目录 一、echo命令二、for循环三、continue和break 一、echo命令 常见转义字符: 转义符号含义-n表示不换行输出\e输出转义字符,将转义后的内容输出到屏幕上\b转义后相当于按退格键,但前提是b后面存在字符: b表示删除前一个字符&#xf…

【Spring篇】IOC/DI配置管理第三方bean

🍓系列专栏:Spring系列专栏 🍉个人主页:个人主页 目录 一、案例:数据源对象管理 1.环境准备 2.实现Druid管理 3.实现C3P0管理 二、加载properties文件 1.第三方bean属性优化 2.读取单个属性 3.注意事项 三、核心容器 1.环境准备 2.容器 1.容器的创建…

linux|进程间通信如何加锁

进程间通信有一种[共享内存]方式,大家有没有想过,这种通信方式中如何解决数据竞争问题?我们可能自然而然的就会想到用锁。但我们平时使用的锁都是用于解决线程间数据竞争问题,貌似没有看到过它用在进程中,那怎么办&…

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

文章目录 💐专栏导读💐文章导读🌷进程是什么🌷进程的描述——PCB🌷进程的组织🌷如何查看进程🌷如何通过系统调用查看进程PID🌷通过系统调用创建进程🌺认识fork&#x1f3…

TuGraph 开源数据库体验

TuGraph 开源数据库体验 文章目录 TuGraph 开源数据库体验1. 简单介绍2. 可视化界面体验:查询界面:数据建模:数据导入: 3. 体验心得: 1. 简单介绍 TuGraph 是蚂蚁集团自主研发的大规模图计算系统,提供图数…

大数据技术之SparkSQL

第1章 Spark SQL概述 1.1 什么是Spark SQL 1)Spark SQL是Spark用于结构化数据(Structured Data)处理的Spark模块。 1.2 为什么要有Spark SQL 1.3 Spark SQL原理 1.3.1 什么是DataFrame (1)DataFrame是一种类似RDD的分…

统计学习方法第四章——朴素贝叶斯法

x.1 前言 朴素贝叶斯法是基于贝叶斯定理与特征条件独立假设的分类方法。是通过给定training dataset学习联合概率分布的方法,是一种生成方法。 x.2 使用贝叶斯定理做分类 使用贝叶斯定理做分类,相比较于朴素贝叶斯即丢除特征条件独立假设这个条件。 …

MySQL主从复制详细介绍

一、主从复制的目的 ​ MySQL内建的复制功能是构建基于MySQL的大规模、高性能应用的基础,复制功能的目的是构建高性能的应用,同时也是高可用性、可扩展性、灾难恢复、备份以及数据仓库等工作的基础。比较常见的用途有以下几种: 数据分布&am…

APP渗透—查脱壳、反编译、重打包签名

APP渗透—查脱壳、反编译、重打包签名 1. 前言1.1. 其它 2. 安装工具2.1. 下载jadx工具2.1.1. 下载链接2.1.2. 执行文件 2.2. 下载apktool工具2.2.1. 下载链接2.2.2. 测试 2.3. 下载dex2jar工具2.3.1. 下载链接 3. 查壳脱壳3.1. 查壳3.1.1. 探探查壳3.1.2. 棋牌查壳 3.2. 脱壳3…

【MiniGPT-4】手把手教部署

最近MiniGPT4开源了,获得了很多网友好评,在Github上获得了1.6万的star,它相比ChatGPT3.5来说,可以实现图片识别,生成想要的文本效果,理解能力非常强。 论文地址:https://github.com/Vision-CAIR…

【大数据之Hadoop】二十一、MapReduce、HDFS、Yarn配合工作(作业提交全过程)

1-11、26为Yarn;12-17为HDFS写数据流程;18-25、27-31为MapReduce;19-25为Shuffle;32-41为HDFS写数据流程。 (0)MR程序提交到客户端所在的节点,在集群模式中运行MR程序,当运行到主函…

数学建模第七天:数学建模算法篇之插值及MATLAB实现

目录 一、前言 1、引例 2、拟合定义 3、拟合与插值的关系 二、拟合 1、线性最小二乘法求解 ①思路 ②解法 2、MATLAB对线性最小二乘拟合的实现 ①函数说明 ②求解例题 3、MATLAB实现非线性曲线拟合 ①lsqcurvefit函数 ②代码求解 4、MATLAB实现非线性最小二乘拟…