Qt中使用QPainter绘制阴影

news2024/10/6 6:10:50

困扰了很久的问题,今天终于明白了如何绘制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 object
    QImage 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 channel
    QImage 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 image
    painter->drawImage(pos - QPointF(blurRadius, blurRadius), tmp);

    // draw source image
    painter->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.coloradmin.cn/o/2191280.html

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

相关文章

在 Ubuntu 安装 Python3.7(没有弯路)

注&#xff1a;当前Ubuntu版本为18.04 下载Python源码包 wget https://www.python.org/ftp/python/3.7.12/Python-3.7.12.tgz安装前准备 安装依赖组件 apt-get updateapt-get install build-essential zlib1g-dev libncurses5-dev libgdbm-dev libnss3-dev libssl-dev libs…

c++----多态(初识)

大家好&#xff0c;今天我们来讲讲我们c中的一个关键知识&#xff0c;叫做多态。但是我们学习多态之前必须将我们前面学习过的继承学习过后才能学习。当然大家可能会先想什么叫多态&#xff0c;我们从名字上上看的话就是多种姿态嘛。毕竟看起来这么容易理解&#xff0c;但其实也…

服务器conda环境安装rpy2

参考博客 https://stackoverflow.com/questions/68936589/how-to-select-r-installation-when-using-rpy2-on-conda 现在我遇到这样一个问题&#xff0c;服务器系统环境没有R(没有权限安装&#xff09;&#xff0c;我只能在minconda的conda环境中使用R, 使用方法如下 我现在…

Rocky Linux 9搭建K8s-1.28.0+docker一主多从集群测试环境

集群类型&#xff1a; Kubernetes集群大体上分为两类&#xff1a;一主多从和多主多从 一主多从&#xff1a;一台master节点和多台node节点&#xff0c;搭建简单&#xff0c;但是有单机故障风险&#xff0c;适用于测试环境 多主多从&#xff1a;多台master节点和多台node节点&am…

ELK日志收集之ES的DSL查询语句

一、简介 在Elasticsearch中&#xff0c;我们可以使用Elasticsearch-DSL(Elasticsearch Domain Specific Language)来构建和执行复杂的搜索查询。官方Query DSL指导文档。 叶查询&#xff1a;在特定字段中寻找特定值,例如 match ,term 或 range。 复合查询&#xff1a;具有查询…

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

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

39 C 语言枚举类型、枚举常量、枚举变量、枚举的遍历、枚举数组、枚举与 switch

目录 1 什么是枚举 2 定义枚举类型 2.1 语法格式 2.2 枚举元素的特点 2.3 案例演示 3 枚举变量 3.1 什么是枚举变量 3.2 定义枚举变量的多种方式 3.3 案例演示 1&#xff1a;标准版枚举类型 3.4 案例演示 2&#xff1a;简化版枚举类型 3.5 案例演示 3&#xff1a;匿…

【教学类-77-01】20241005青花瓷立体书

背景需求&#xff1a; 今天翻到小红书上一个青花瓷立体书 &#x1f1ed;&#x1f1f0;香港免费展览&#xff5c;青花瓷立体纸艺观展册&#x1f4d6; - 小红书 (xiaohongshu.com)https://www.xiaohongshu.com/discovery/item/6426a8fb000000001303653e?app_platformandroid&a…

买卖股票大合集

刷题刷题往死里刷。 121. 买卖股票的最佳时机 链接 121. 买卖股票的最佳时机 思路&#xff1a; 二次做所以有思路了&#xff0c; 从头遍历数组&#xff0c;维持一个最小值&#xff0c;且遇到一个值就计算差值&#xff0c;且维护这个最大值为答案。 class Solution {public …

文心智能体——制作你的专属AI

随着社会的进步和互联网技术的发展&#xff0c;人工智能领域正蓬勃发展。最近几年关于人工智能的新闻日渐增多并且成为了当代最大的热点&#xff0c;所有的领域都在引进AI、训练AI、使用AI&#xff0c;AI正逐步融入人们的生活。从前几年chatGPT大语言模型的横空出世&#xff0c…

【CSDN入门级教程】

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Linux进程调度和进程切换

并行&#xff08;Parallel&#xff09; 含义&#xff1a;并行是指多个任务在同一时刻同时执行。 硬件要求&#xff1a;需要多个处理器&#xff08;如多核CPU&#xff09;或者多台计算设备来实现&#xff0c;这些执行单元能够真正地同时处理不同的任务。例如&#xff0c;一个具…

vite学习教程05、vite+vue2构建本地 SVG 图标

文章目录 前言一、构建本地SVG图标详细步骤1、安装开发依赖2、配置vite2.1、配置vite.config.js2.2、封装vite引入插件脚本 解决报错&#xff1a;can not find package fast-glob imported 二、实际应用应用1&#xff1a;未封装&#xff0c;直接vue应用应用2&#xff1a;封装vu…

Self-Operating Computer:基于PyAutoGui加AI实现无人“驾驶“电脑,让Python带你走近未来世界

近年来&#xff0c;AI 领域不断取得突破&#xff0c;特别是多模态模型的出现&#xff0c;为计算机无人操控带来了全新的可能性。 想象一下&#xff0c;你的电脑不再需要你手动操作&#xff0c;而是可以像人一样&#xff0c;理解你的指令&#xff0c;并自动执行一系列鼠标键盘操…

【word脚注】双栏设置word脚注,脚注仅位于左栏,右栏不留白

【word脚注】双栏设置word脚注&#xff0c;脚注仅位于左栏&#xff0c;右栏不留白 调整前效果解决方法调整后效果参考文献 调整前效果 调整前&#xff1a;脚注位于左下角&#xff0c;但右栏与左栏内容对其&#xff0c;未填充右下角的空白区域 解决方法 备份源文件复制脚注内…

MySQL--聚合查询、联合查询、子查询、合并查询(上万字超详解!!!)

目录 一、前言二、聚合查询2.1 聚合函数2.1.1 COUNT():统计所有行2.1.2 SUM(列名) 求和2.1.3 AVG()2.1.4 MAX()、MIN() 2.2 GROUP BY子句&#xff08;分组查询&#xff09;2.3 HAVING 三、联合查询3.1表的笛卡儿积3.2内连接3.2.1 例题一3.2.2 例题二 3.3外连接3.3.1 右外连接3.…

【每天学个新注解】Day 16 Lombok注解简解(十五)—@FieldNameConstants

FieldNameConstants 根据属性名生成常量类的常量。 1、如何使用 加在需要根据属性名生成常量的属性上。 2、代码示例 例&#xff1a; FieldNameConstants public class Test {private String iAmAField;private int andSoAmI;FieldNameConstants.Exclude private int asA…

Microsoft AI部门的CEO额备忘录

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

kafka-windows集群部署

kafka-windows集群部署目录 文章目录 kafka-windows集群部署目录前言一、复制出来四个kafka文件夹二、修改集群每个kafka的配置文件四、启动zookeeper&#xff0c;kafka集群 前言 部署本文步骤可以先阅读这一篇博客&#xff0c;这篇是关于单机kafka部署测试的。本文用到的文件…

VUE2常见问题以及解决方案汇总(不断更新中)

解决vue项目中 el-table 的 row-click 事件与行内点击事件冲突&#xff0c;点击事件不生效&#xff08;表格行点击事件和行内元素点击事件冲突&#xff09;需要阻止事件冒泡 问题描述 1.点击列的编辑按钮&#xff0c;会触发按钮本身事件&#xff0c;同时会触发行点击事件 2.点…