Qt桌面白板工具其三(解决半透明桌面画布刷新透明像素时产生耗时,导致的画笔卡顿问题)

一、问题
前两篇文章写了很多有关桌面画板的实现方法,这个过程中,画笔的卡顿问题还是无法彻底解决。
先简单回顾一下我实现桌面画板的逻辑;
1.父窗口:一个透明窗口,通过设置带有透明度的QColor bg_color,以及在paintEvent中整个窗口刷透明颜色。通过切换bg_color的alpha通道,来实现画布的穿透效果或透明绘制效果,没有透明度的白色则为白板。

	QPainter painter(this);painter.fillRect(this->rect(), bg_color);

2.绘图子窗口,布局在父窗口内,完全透明,主要负责实际产生的QImage图像的刷新。
在该窗口中重载了相应的鼠标函数,通过搜集一系列的鼠标经过点,来对QImage进行绘制。有关QPainter绘制QImage的内容不再赘述。最后,在该类的paintEvent中,将整张QImage刷新上去,实现绘制效果。
为了实现实时的刷新,有两种思路。
(1)在moveEvent搜集点,绘制QImage的同时,update()触发paintEvent
(2)通过定时器,每30ms刷新一次update,将QImage绘制上去。这基本上是主流相机的图片帧帧率了
在我电脑上统计,每一秒会触发900余次moveevent,相当于搜集了900多个点。在进行临近点的过滤后,仍然有500余点,即会触发500次update(因为update不是实时刷新,内部有优化,所以实际上不是这么多。)这样的话,paintEvent过于频繁,在内部产生的耗时会造成moveEvent触发过少,导致绘图卡顿,是恶性循环。所以,第二种方法较好。

可即便如此,采用定时器触发,在触发定时时,仍会造成moveEvent的阻塞,造成规律性的绘图卡顿,即期望通过鼠标绘制一条圆滑曲线,结果线段会规律地出现折线。

二、问题查找过程
通过繁琐的检测耗时,我发现在moveEvent中,对QImage实时绘制线段,其实是极低的,因为绘制(刷新)区域仅线段所在的范围;
而在paintEvent中,将一整张图绘制上窗口时,耗时比较严重,有25ms左右。
我又对比了QPixmap和QImage之间的效率,发现相差不大,又在窗口内塞入了一个QLabel,想要另辟蹊径,结果都不理想
最终,我发现了造成25ms延时的问题所在:子窗口触发paintEvent的同时,父窗口也会触发paintEvent,即我每一次刷新我的QImage图像时,都还会让父窗口刷一遍半透明像素颜色…
通过检测耗时,确定就是该处造成的原因

三、问题分析与解决办法
如果,父窗口不是透明的,速度立马上来了,曲线变得圆滑,简直完美!可无奈,我需要半透明画板,因为我要实现桌面画板,对ppt啊啥的进行实时标注嘛。
这就很让人头疼,因为尝试了其他半透明窗口的实现,都不理想。于是我想到了,干脆不要父窗口了,在子窗口中,半透明像素的刷新和QImage的显示,同步在paintEvent中做……
结果就是,跟之前是一毛一样的效果,都是卡!
而如果强行把半透明刷新和QImage拆开,可能会造成一些奇怪的问题,比如单次绘制之后,因为没有触发半透明刷新,导致窗口直接穿透了的bug

需要明确,半透明像素颜色刷新,是必须的。但我思考了下,其实不需要全部刷新,即不需要整个窗口区域的刷新。qt的update非常友好地提供了区域刷新的功能,即

update(QRect(x,x,x,x));

刷新的时候,我直接传入一个计算好的矩形,即可避免上述25ms耗时的产生。
是不是茅塞顿开?hh
不过,我还是采用了上述在子窗口中同时刷新半透明像素点和QImage的方法,然后将父窗口直接完全透明处理了。
那,剩下的就是刷新区域的计算问题了。
刷新半透明像素点,本质上也是刷新QImage,所以QRect的区域,在我们moveEvent中采集点的过程中,实时去计算,目的是将“本次update的线段”都包含在QRect中。
因为考虑线宽的问题,实际上QRect还要再往外扩一下,详细代码就不贴了。
因为update传递了坐标,所以系统优化的时候,不会平白无故忽略了某一次,造成有其中一次线段不显示的情况。

至此,这个困扰我依旧的问题终于解决。效果嘛,算是比较流畅了。

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

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

相关文章

高级语言讲义2016计专(仅高级语言部分)

1.斐波那契序列的第n项可以表示成以下形式&#xff0c;编写一个非递归函数&#xff0c;返回该数列的第n项的数值 #include <stdio.h>int func(int n) {if(n1||n2)return 1;int p1,q1,num;for(int i3; i<n; i) {numpq;qp;pnum;}return num; } 2.在MXN的二维数组A中&am…

Django框架连接数据库

这里以同时连接sqlite、mysql、redis为例 首先要下载对应的sqlite、mysql、redis相应的模块插件 开始上代码 settings.py 配置文件 import os # 引入mysql模块 import pymysql # pymysql.install_as_MySQLdb()来确保pymysql能够兼容这些代码 pymysql.install_as_MySQLdb()# 数…

Go中的控制反转 IoC

以嵌入组合的方式实现控制反转 IoC: 控制反转是一种解耦思想&#xff0c;将原本耦合在业务逻辑中的控制逻辑单独拆出来实现&#xff0c;不再让业务逻辑在处理业务的同时还要去实现控制逻辑&#xff0c;而是专注处理业务。在业务逻辑代码中耦合进控制逻辑&#xff0c;会导致在编…

window搭建本地mongo数据库并导入数据

1 window下载mongo数据库 官网&#xff1a;www.mongodb.com 选择 Products > Community Edition 就能进入社区版 在这里下载 windows 版对应的安装包 注意&#xff1a;6.0.1 版本的 MongoDB 配置环境变量有问题&#xff0c;并且我不知道怎么解决&#xff0c;如果想要避免出…

算法学习05:离散化、区间合并

算法学习05&#xff1a;离散化、区间合并 文章目录 算法学习05&#xff1a;离散化、区间合并前言需要记忆的模版&#xff1a;一、离散化1.例题&#xff1a;离散化 区间和&#xff1a;拓展: 二、区间合并&#xff08;贪心&#xff09;1.例题&#xff1a; 总结 前言 需要记忆的模…

基于FastAPI构造一个AI模型部署应用

前言 fastapi是目前一个比较流行的python web框架&#xff0c;在大模型日益流行的今天&#xff0c;其云端部署和应用大多数都是基于fastapi框架。所以掌握和理解fastapi框架基本代码和用法尤显重要。 需要注意的是&#xff0c;fastapi主要是通过app对象提供了web服务端的实现代…

tidyverse提取MergedGenes列包含“sss“字符的行

要使用tidyverse包在R中提取包含特定字符串“sss”字符的MergedGenes列的行&#xff0c;可以使用dplyr包中的filter()函数和str_detect()函数来实现。这里的str_detect()函数来自stringr包&#xff0c;它是tidyverse的一部分&#xff0c;用于检测字符串是否符合给定的模式。以下…

基于php的用户登录实现(v1版)(持续迭代)

目录 版本说明 数据库连接 登录页面&#xff1a;login.html 登录处理实现&#xff1a;login.php 用户欢迎页面&#xff1a;welcome.php 用户注册页面&#xff1a;register.html 注册执行&#xff1a;DoRegister.php 版本说明 v1实现功能&#xff1a; 数据库连接&#x…

SOCKS5代理与网络安全的舞蹈

在这个信息爆炸的时代&#xff0c;网络安全成为了每个网民乃至每个软件工程师的头等大事。今天&#xff0c;我们要聊的是如何使用SOCKS5代理和代理IP来保护我们的网络安全&#xff0c;同时还不失趣味性。这听起来可能有点枯燥&#xff0c;但别担心&#xff0c;我们会用一种轻松…

自定义限流注解

自定义注解 /*** 速率限制注解** author: 张定辉* date: 2024/3/5 21:29* description: 速率限制注解*/ Target({ElementType.TYPE,ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) public interface RateLimit {/*** SPEL表达式* <p>* 1.使用方法的基本类型参…

SpringAOP面向切面编程-代理

目录 1.静态代理 2.动态代理 代理在开发中实现的方式具体有两种&#xff1a;静态代理&#xff0c;[动态代理技术] 1.静态代理 主动创建代理类 public class CalculatorStaticProxy implements Calculator {// 将被代理的目标对象声明为成员变量private Calculator target;…

面试问答之MySQL数据库进阶

文章目录 &#x1f412;个人主页&#xff1a;信计2102罗铠威&#x1f3c5;JavaEE系列专栏&#x1f4d6;前言&#xff1a;&#x1f380; MySQL架构&#x1f415;数据库引擎&#x1f415; InnoDB存储存储引擎&#x1f415;MYISAM &#x1f3e8;索引&#x1f415;哪些情况需要创建…

vue3+element-plus el-input 自动获取焦点

虽然element有提供input的autofocus属性&#xff0c;但是当我们第二次进入页面就会发现autofocus已经不再生效&#xff0c;需要通过onMounted去触发input的focus解决这个问题。 1.先给el-input绑定一个ref&#xff1a;<el-input ref"inputRef" v-model"inp…

景联文科技:专业提供高质量大语言模型训练数据

2024年&#xff0c;数字经济被再次写入政府工作报告中&#xff0c;报告指出要深化大数据、人工智能等研发应用&#xff0c;打造具有国际竞争力的数字产业集群。 大模型作为生成式人工智能的基础&#xff0c;日益成为国际科技竞争的焦点。人大代表杨剑宇指出&#xff0c;尽管我国…

008-slot插槽

slot插槽 1、插槽 slot 的简单使用2、插槽分类2.1 默认插槽2.2 具名插槽2.3 作用域插槽 插槽就是子组件中的提供给父组件使用的一个占位符&#xff0c;用<slot></slot> 表示&#xff0c;父组件可以在这个占位符中填充任何模板代码&#xff0c;如 HTML、组件等&…

老阳分享:视频号带货的四大技巧

视频号带货作为新兴的电商模式&#xff0c;在微信这个庞大的社交平台上展现出了巨大的潜力。要想在视频号带货领域取得成功&#xff0c;需要掌握一定的技巧。本文将为您详细解析视频号带货的四大技巧&#xff0c;感兴趣的朋友一起去看看吧。 一、内容创新 内容创新是视频号带货…

【深度学习笔记】5_11 残差网络ResNet

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 5.11 残差网络&#xff08;ResNet&#xff09; 让我们先思考一个问题&#xff1a;对神经网络模型添加新的层&#xff0c;充分训练后的…

Express框架的产生

Express框架的产生&#xff0c;解决的痛点是什么&#xff1f; 1.优化Node.js在Web的开发 Express框架是一个基于Node.js的Web应用程序开发框架&#xff0c;它的产生主要是为了解决Node.js在Web开发中的一些痛点。 在Node.js出现之前&#xff0c;Web开发主要是基于传统的后端…

springboot项目集成,项目流程概述

一、项目介绍 二、项目设计原则 2.1整体原则 2.2持久层 2.3业务逻辑层 具体分析 三、实战 3.1项目搭建 <dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-crypto</artifactId></dependency>&l…

双链表的实现(数据结构)

链表总体可以分为三大类 一、无头和有头 二、单向和双向 三、循环和不循环 从上面分类得知可以组合成8种不同类型链表&#xff0c;其中单链表最为简单&#xff0c;双联表最为复杂&#xff0c;两种链表都实现后其余链表都不成问题。 我们前期博客已将完成了单向无头不循环链表…