Qt中使用QPainter绘制阴影

困扰了很久的问题,今天终于明白了如何绘制QGraphicDropShadowEffect同样效果的阴影,故写下这篇文章分享给大家。其方法是复制Qt源代码中QGraphicDropShadowEffect绘制实现的核心代码然后稍作修改实现,先看效果和封装过后的源代码:
draw-shadow
头文件:

#pragma once#include <qwidget.h>class CustomWidget : public QWidget {
public:explicit CustomWidget(QWidget *parent = nullptr);protected:void paintEvent(QPaintEvent *event) override;private:/*** @brief 为对象绘制阴影* @param painter* @param shadowObjectPixCache 对象临时缓冲图形* @param pos 绘制位置* @param blurRadius 阴影半径* @param color 阴影颜色* @param offset 偏移*/static void drawShadow(QPainter* painter, const QPixmap &shadowObjectPixCache, const QPointF& pos, qreal blurRadius, const QColor &color, const QPointF &offset);
};

源文件:

#include "customwidget.h"#include <qpainter.h>
#include <qmath.h>CustomWidget::CustomWidget(QWidget *parent): QWidget(parent)
{}void CustomWidget::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.fillRect(rect(), 0x35363C);QRect drawRect(0, 0, 100, 100);// 创建缓存图片在上面绘制图形QPixmap cacheImage(drawRect.width(), drawRect.height());cacheImage.fill(Qt::transparent);QPainter cachePainter(&cacheImage);cachePainter.setRenderHint(QPainter::Antialiasing);cachePainter.setBrush(QColor(0x26282D));cachePainter.setPen(Qt::NoPen);// 绘制一个圆角矩形cachePainter.drawRoundedRect(drawRect, 9, 9);cachePainter.end();// 左上角auto topLeft = rect().center() - drawRect.center();// 绘制图片和阴影drawShadow(&painter, cacheImage, topLeft, 6, 0x6B6F79, QPointF(0, 0));
}// Qt internal function (qtbase/src/widgets/effects/qpixmapfilter.cpp)
extern void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed);// qtbase/src/widgets/effects/qpixmapfilter.cpp: line 1317
void CustomWidget::drawShadow(QPainter* painter, const QPixmap &shadowObjectPixCache, const QPointF& pos, qreal blurRadius, const QColor &color, const QPointF &offset) {// temp render objectQImage tmp(shadowObjectPixCache.size() + QSize(qCeil(blurRadius * 2), qCeil(blurRadius * 2)), QImage::Format_ARGB32_Premultiplied);tmp.setDevicePixelRatio(shadowObjectPixCache.devicePixelRatioF());tmp.fill(0);QPainter tmpPainter(&tmp);tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);tmpPainter.drawPixmap(QPointF(blurRadius, blurRadius) + offset, shadowObjectPixCache);tmpPainter.end();// blur the alpha channelQImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);blurred.setDevicePixelRatio(shadowObjectPixCache.devicePixelRatioF());blurred.fill(0);QPainter blurPainter(&blurred);qt_blurImage(&blurPainter, tmp, blurRadius, false, true, 0);blurPainter.end();tmp = std::move(blurred);// blacken the image...tmpPainter.begin(&tmp);tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);tmpPainter.fillRect(tmp.rect(), color);tmpPainter.end();// draw shadow imagepainter->drawImage(pos - QPointF(blurRadius, blurRadius), tmp);// draw source imagepainter->drawPixmap(pos, shadowObjectPixCache);
}

跟上面的示例一样,在绘制阴影之前先创建一个缓存图片,再调用drawShadow创建阴影。上面代码中的drawShadow正是复制的Qt源代码qtbase/src/widgets/effects/qpixmapfilter.cpp第1317行(Qt5.15.2)的阴影绘制函数,然后稍作修改实现。然后其中用到的一个关键函数qt_blurImage为Qt内部函数,这里仅声明就可以直接导出来使用。看了源代码后就明白了为什么有时候QGraphicDropShadowEffect绘制效率很低界面卡顿,其原因是创建了两个相同大小的临时图片和qt_blurImage的计算导致的。因此在使用该方法的时候,最好使用双缓冲的方式在大小不变的情况下只绘制一次阴影。其他类型的阴影都可以参考qpixmapfilter.cpp中的实现。

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

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

相关文章

深度探索Kali Linux的精髓与实践应用

Kali Linux简介 Kali Linux作为全球网络安全领域的首选操作系统之一&#xff0c;其强大的功能性及广泛的适用范围令人瞩目。除了上述基础介绍外&#xff0c;让我们深入探究Kali Linux的几个关键特性及其在实际操作中的具体应用案例。 Kali工具集成&#xff1a;全面的安全工具…

计算机视觉——图像修复综述篇

目录 1. Deterministic Image Inpainting 判别器图像修复 1.1. sigle-shot framework (1) Generators (2) training objects / Loss Functions 1.2. two-stage framework 2. Stochastic Image Inpainting 随机图像修复 2.1. VAE-based methods 2.2. GAN-based methods …

【C++】“list”的介绍和常用接口的模拟实现

【C】“list”的介绍和常用接口的模拟实现 一. list的介绍1. list常见的重要接口2. list的迭代器失效 二. list常用接口的模拟实现&#xff08;含注释&#xff09;三. list与vector的对比 一. list的介绍 list是可以在常数范围内在任意位置进行插入和删除的序列式容器&#xf…

国庆普及模拟赛-5

题目链接&#xff1a; file:///C:/Users/Administrator/Desktop/%E4%B8%8B%E5%8F%91%E6%96%87%E4%BB%B61005/20241005.pdf T1&#xff1a; 题目分析&#xff1a;不需要进行模拟&#xff0c;想要获得分数最大化&#xff0c;只需要将大的数据相加&#xff0c;再减去小的数据。 …

C语言进阶版第16课—自定义类型:结构体

文章目录 1. 结构体类型的声明和初始化2. 结构体自引用3. 结构体内存对齐3.1 结构体内存对齐规则3.2 修改默认对齐数 4. 结构体传参4. 结构体实现位段5. 位段使用的注意事项 1. 结构体类型的声明和初始化 结构体在使用之前都要对其类型进行声明&#xff0c;关键字是struct&…

Pandas -----------------------基础知识(主要matplotlib知识)(七)

Dataframe变形 转置 T import pandas as pddata {2022: [10, 30, 15, 20], 2023: [40, 50, 36, 21]} df1 pd.DataFrame(data, index[q1, q2, q3, q4]) print("原始数据框&#xff1a;") print(df1)df2 df1.Tprint("转换后数据框&#xff1a;") print(df…

计算机视觉算法知识详解(含代码示例)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

FRP搭建内网穿透:云服务端 + 家用Linux/Windows主机【2024】

介绍 FRP是一个可以自己搭建内网穿透服务的开源项目&#xff0c;开源地址直达&#xff1a; FRP-GitHub 实际上frp由两个程序组成 ①frps:在服务端运行的程序 ②frpc:在客户端运行的程序 运作方式示意图如下 服务端 因为服务上使用了1Panel面板&#xff0c;直接在应用商店安…

【算法系列-链表】删除链表的倒数第N个结点

【算法系列-链表】删除链表的倒数第N个结点 文章目录 【算法系列-链表】删除链表的倒数第N个结点1. 算法分析&#x1f6f8;2. 模拟解决问题2.1 思路分析&#x1f3af;2.2 代码示例&#x1f330; 3. 双指针(快慢指针)解决问题3.1 思路分析&#x1f3af;3.2 代码示例&#x1f330…

软件验证与确认实验二-单元测试

目录 1. 实验目的及要求.................................................................................................... 3 2. 实验软硬件环境.................................................................................................... 3 …

进阶岛第4关:InternVL 多模态模型部署微调实践

准备InternVL模型 我们使用InternVL2-2B模型。该模型已在share文件夹下挂载好&#xff0c;现在让我们把移动出来。 mkdir -p /root/project/joke/modelcp -r /root/share/new_models/OpenGVLab/InternVL2-2B /root/project/joke/model # 不用ln -s 准备环境 这里我们来手动配…

Brave编译指南2024 MacOS篇-构建与运行(六)

引言 在上一篇文章中&#xff0c;我们成功初始化了Brave浏览器的构建环境。现在&#xff0c;我们进入了这个编译指南的核心部分&#xff1a;实际构建Brave浏览器并运行它。这个过程将把我们之前准备的所有源代码和依赖项转化为一个可运行的浏览器实例。 1. 编译Brave浏览器 …

【进阶OpenCV】 (5)--指纹验证

文章目录 指纹验证1. 验证原理2. 读取图片3. 计算特征匹配点 总结 指纹验证 指纹验证基于人类指纹的独特性和稳定性。每个人的指纹在图案、断点和交叉点上各不相同&#xff0c;这种唯一性和终生不变性使得指纹成为身份验证的可靠手段。指纹识别技术通过采集和分析指纹图像&…

docker 部署nacos

目录 一、拉取镜像 二、部署 三、访问&#xff08;默认是用内嵌数据库&#xff09; 四、配置 五、重启容器 一、拉取镜像 docker pull nacos/nacos-server 二、部署 docker run --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 --restartalways --privilegedt…

算法笔记(十)——队列+宽搜

文章目录 N 叉数的层序遍历二叉树的锯齿形层序遍历二叉树最大宽度在每个树行中找最大值 BFS是图上最基础、最重要的搜索算法之一&#xff1b; 每次都尝试访问同一层的节点如果同一层都访问完了&#xff0c;再访问下一层 BFS基本框架 void bfs(起始点) {将起始点放入队列中;标记…

Docker启动 Redis提示:Can‘t initialize Background Jobg

问题说明: 在使用docker启动redis失败&#xff0c;但是查看容器日志&#xff0c;除了提示 Fatal:Cant initialize Background Jobg&#xff0c;没有其他错误信息。经过长时间查找资料及试错&#xff0c;现记录下可能的产生原因及解决方案&#xff0c;以便以后参考。 产生原因&…

【漏洞复现】锐捷 RG-EW1200G 无线路由器 登录绕过

》》》产品描述《《《 锐捷网络RG-EW1200G是一款有线无线全千兆双频无线路由器Q&#xff0c;适合平层家居、别墅、小型店铺、SOHO办公等场景使用。设备性能卓越&#xff0c;足以满足千兆上网需求;信号强劲&#xff0c;信号功率功率提升3倍&#xff0c;覆盖距离提升近1倍覆盖能力…

【Linux】进程间关系与守护进程

超出能力之外的事&#xff0c; 如果永远不去做&#xff0c; 那你就永远无法进步。 --- 乌龟大师 《功夫熊猫》--- 进程间关系与守护进程 1 进程组2 会话3 控制终端4 作业控制5 守护进程 1 进程组 之前我们提到了进程的概念&#xff0c; 其实每一个进程除了有一个进程 ID(P…

算法: 二分查找题目练习

文章目录 二分查找二分查找在排序数组中查找元素的第一个和最后一个位置搜索插入位置x 的平方根山脉数组的峰顶索引寻找峰值寻找旋转排序数组中的最小值点名 总结精华模版 二分查找 二分查找 没啥可说的,轻轻松松~ class Solution {public int search(int[] nums, int target…

Pragmatic Task务实任务——指导语义通信的优化

1. 语义通信 语义通信&#xff08;Semantic Communication&#xff09;的核心理念是传递不仅仅是数据本身&#xff0c;而是数据所包含的“语义”或“意义”。这与传统通信系统不同&#xff0c;传统系统只注重如何准确、高效地传输数据&#xff0c;而语义通信则要求传输的信息能…