当前位置: 首页 > article >正文

QT:paintEvent、QPainter、QPaintDevice

paintEvent 介绍

在 Qt 编程中,paintEvent 是 QWidget 类中的一个非常重要的虚函数,用于处理绘图事件。当一个 QWidget 或其派生类的实例需要进行重绘操作时,Qt 会自动调用该控件的 paintEvent 函数。

触发时机

窗口首次显示:当一个窗口或控件第一次显示在屏幕上时,会触发 paintEvent 来绘制其初始外观。
窗口大小改变:当用户调整窗口大小,或者通过代码改变窗口大小时,为了适应新的尺寸,会触发 paintEvent 重新绘制内容。
窗口被遮挡后恢复显示:如果窗口被其他窗口遮挡,之后遮挡窗口移开,窗口需要重新绘制可见部分,此时会触发 paintEvent。
调用 update() 或 repaint() 方法:在代码中调用 update() 或 repaint() 方法可以手动触发 paintEvent。update() 会在 Qt 的事件循环中安排一次重绘,它会合并多个 update() 调用以避免不必要的重绘;而 repaint() 会立即触发重绘操作。

void QWidget::paintEvent(QPaintEvent *event);

QPaintEvent *event 是一个指向 QPaintEvent 对象的指针,该对象包含了与绘制事件相关的信息,例如需要重绘的区域(通过 event->rect() 可以获取)。

响应窗口大小变化

#include <QApplication>
#include <QWidget>
#include <QPainter>class ResizableWidget : public QWidget {
public:ResizableWidget(QWidget *parent = nullptr) : QWidget(parent) {}protected:void paintEvent(QPaintEvent *event) override {Q_UNUSED(event);QPainter painter(this);// 绘制一个与窗口大小相关的矩形int x = width() / 4;int y = height() / 4;int w = width() / 2;int h = height() / 2;painter.drawRect(x, y, w, h);}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);ResizableWidget widget;widget.setWindowTitle("Resizable Drawing");widget.resize(300, 300);widget.show();return app.exec();
}

定义了 ResizableWidget 类,重写 paintEvent 函数。
在 paintEvent 中,根据窗口的当前宽度和高度计算矩形的位置和大小,然后绘制矩形。这样当窗口大小改变时,矩形会自动调整以适应新的窗口尺寸。
在这里插入图片描述

QPainter

QPainter 是 Qt 框架中用于执行 2D 绘图操作的核心类。它提供了丰富的 API,允许开发者在各种 QPaintDevice(如画布、窗口、图像等)上绘制基本图形(如点、线、矩形、椭圆等)、文本、图像,还能应用渐变、变换等效果,从而实现复杂的图形和界面绘制。

QPainter 的主要特点和功能包括:

基本图形绘制:支持绘制点、线、矩形、椭圆、多边形等多种基本图形。
文本绘制:可以在指定位置绘制文本,并能设置字体、颜色、对齐方式等属性。
图像绘制:能够将图像绘制到指定位置,还可以进行缩放、旋转等操作。
渐变填充:支持线性渐变、径向渐变、锥形渐变等填充效果。
变换操作:如平移、旋转、缩放等,可对绘制的图形进行变换。
抗锯齿:可以开启抗锯齿功能,使绘制的图形边缘更加平滑。

绘制基本图形

#include <QApplication>
#include <QWidget>
#include <QPainter>class DrawingWidget : public QWidget {
protected:void paintEvent(QPaintEvent *event) override {Q_UNUSED(event);QPainter painter(this);// 绘制直线painter.drawLine(20, 20, 200, 20);// 绘制矩形painter.drawRect(20, 40, 180, 100);// 绘制椭圆painter.drawEllipse(20, 160, 180, 100);}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);DrawingWidget widget;widget.setWindowTitle("Basic Shapes Drawing");widget.resize(300, 300);widget.show();return app.exec();
}

在这里插入图片描述

DrawingWidget 类继承自 QWidget,并重写了 paintEvent 方法,在该方法中进行绘图操作。
QPainter 对象 painter 用于实际的绘图,它以 this(即 DrawingWidget 实例)作为绘图设备。
drawLine 方法用于绘制直线,传入起点和终点的坐标。
drawRect 方法绘制矩形,参数分别为矩形左上角的坐标以及矩形的宽度和高度。
drawEllipse 方法绘制椭圆,参数与矩形类似。

绘制文本

#include <QApplication>
#include <QWidget>
#include <QPainter>class TextDrawingWidget : public QWidget {
protected:void paintEvent(QPaintEvent *event) override {Q_UNUSED(event);QPainter painter(this);// 设置字体QFont font("Arial", 20);painter.setFont(font);// 设置文本颜色painter.setPen(Qt::blue);// 绘制文本painter.drawText(50, 100, "Hello, Qt!");}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);TextDrawingWidget widget;widget.setWindowTitle("Text Drawing");widget.resize(300, 300);widget.show();return app.exec();
}

创建 QFont 对象设置字体的名称和大小,并通过 setFont 方法将其应用到 QPainter 上。
setPen 方法设置文本的颜色为蓝色。
drawText 方法在指定位置绘制文本,第一个参数是文本左上角的横坐标,第二个参数是纵坐标,第三个参数是要绘制的文本内容。

在这里插入图片描述

变换操作

#include <QApplication>
#include <QWidget>
#include <QPainter>class TransformationWidget : public QWidget {
protected:void paintEvent(QPaintEvent *event) override {Q_UNUSED(event);QPainter painter(this);// 保存当前的绘图状态painter.save();// 平移坐标系painter.translate(width() / 2, height() / 2);// 旋转坐标系painter.rotate(45);// 绘制旋转后的矩形painter.drawRect(-50, -25, 100, 50);// 恢复之前保存的绘图状态painter.restore();}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);TransformationWidget widget;widget.setWindowTitle("Transformation Drawing");widget.resize(300, 300);widget.show();return app.exec();
}

save 方法保存当前的绘图状态,包括坐标系、画笔、画刷等属性。
translate 方法将坐标系原点平移到窗口的中心。
rotate 方法将坐标系旋转 45 度。
绘制矩形时,使用的是平移和旋转后的坐标系。
restore 方法恢复之前保存的绘图状态,以便后续绘图不受影响。
在这里插入图片描述

QPaintDevice

QPaintDevice 是 Qt 中所有可以进行绘制操作的对象的基类,它为 QPainter 提供了一个绘图的目标设备抽象接口。也就是说,QPainter 可以在任何继承自 QPaintDevice 的对象上进行绘图操作,比如窗口、图像、打印机等。

主要特点

抽象性:QPaintDevice 是一个抽象基类,不能直接实例化,它定义了一些纯虚函数,这些函数由具体的子类来实现,从而实现不同类型设备的绘图功能。
多设备支持:Qt 提供了多个继承自 QPaintDevice 的子类,常见的有 QWidget(用于窗口和控件)、QImage(用于内存中的图像)、QPixmap(用于屏幕优化的图像)、QPrinter(用于打印机)等,这使得开发者可以在不同的设备上进行统一的绘图操作。
与 QPainter 协作:QPainter 是绘图的执行者,而 QPaintDevice 是绘图的目标,二者紧密协作完成绘图任务。在使用 QPainter 进行绘图时,需要在构造函数中传入一个 QPaintDevice 对象作为参数。

常用子类及用途

QWidget:用于创建窗口和各种用户界面控件,QWidget 的 paintEvent 函数中通常会使用 QPainter 在窗口上进行绘图。
QImage:可以在内存中创建和操作图像,它支持直接访问像素数据,适合进行图像处理和生成图像文件。
QPixmap:是一种专门为屏幕显示优化的图像表示,它可以高效地在屏幕上绘制,常用于快速显示图像。
QPrinter:用于将绘图内容输出到打印机,实现打印功能。

在 QWidget 上绘图

#include <QApplication>
#include <QWidget>
#include <QPainter>class DrawingWidget : public QWidget {
public:DrawingWidget(QWidget *parent = nullptr) : QWidget(parent) {}protected:void paintEvent(QPaintEvent *event) override {Q_UNUSED(event);QPainter painter(this);  // this 是 QWidget 对象,作为 QPaintDevicepainter.setPen(Qt::blue);painter.drawLine(20, 20, 200, 20);}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);DrawingWidget widget;widget.setWindowTitle("Drawing on QWidget");widget.resize(300, 200);widget.show();return app.exec();
}

在这里插入图片描述
定义了一个自定义的 DrawingWidget 类,继承自 QWidget。
在 paintEvent 函数中,创建了一个 QPainter 对象,将 this(即 DrawingWidget 实例,它是 QWidget 类型,继承自 QPaintDevice)作为绘图设备。
使用 QPainter 的 setPen 方法设置画笔颜色为蓝色,然后调用 drawLine 方法在窗口上绘制一条直线

在 QImage 上绘图并保存为文件

在这里插入图片描述

#include <QApplication>
#include <QImage>
#include <QPainter>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建一个 QImage 对象作为绘图设备QImage image(200, 200, QImage::Format_RGB32);image.fill(Qt::white);  // 填充背景为白色QPainter painter(&image);  // 将 QImage 作为绘图设备painter.setPen(Qt::red);painter.drawRect(50, 50, 100, 100);painter.end();  // 结束绘图// 保存图像为文件image.save("output.png", "PNG");return app.exec();
}

创建了一个 QImage 对象,指定了图像的宽度、高度和像素格式。
使用 fill 方法将图像背景填充为白色。
创建 QPainter 对象,将 QImage 对象的指针作为绘图设备传入。
使用 QPainter 的 setPen 方法设置画笔颜色为红色,然后调用 drawRect 方法在图像上绘制一个矩形。
调用 end 方法结束绘图操作。
最后使用 save 方法将绘制好的图像保存为 output.png 文件。

使用 QPrinter 打印图形

QT       += core gui printsupport
#include <QApplication>
#include <QPrinter>
#include <QPainter>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建一个 QPrinter 对象QPrinter printer;printer.setOutputFormat(QPrinter::PdfFormat);printer.setOutputFileName("output.pdf");// 创建 QPainter 对象,将 QPrinter 作为绘图设备QPainter painter(&printer);painter.setPen(Qt::green);painter.drawEllipse(50, 50, 100, 100);painter.end();return app.exec();
}

创建了一个 QPrinter 对象,并设置输出格式为 PDF,指定输出文件名为 output.pdf。
创建 QPainter 对象,将 QPrinter 对象的指针作为绘图设备传入。
使用 QPainter 的 setPen 方法设置画笔颜色为绿色,然后调用 drawEllipse 方法绘制一个椭圆。
调用 end 方法结束绘图操作,此时绘制的内容会被输出到指定的 PDF 文件中。

在这里插入图片描述

相关文章:

QT:paintEvent、QPainter、QPaintDevice

paintEvent 介绍 在 Qt 编程中&#xff0c;paintEvent 是 QWidget 类中的一个非常重要的虚函数&#xff0c;用于处理绘图事件。当一个 QWidget 或其派生类的实例需要进行重绘操作时&#xff0c;Qt 会自动调用该控件的 paintEvent 函数。 触发时机 窗口首次显示&#xff1a;当…...

OpenHarmony-4.基于dayu800 GPIO 实践(2)

基于dayu800 GPIO 进行开发 1.DAYU800开发板硬件接口 LicheePi 4A 板载 2x10pin 插针&#xff0c;其中有 16 个原生 IO&#xff0c;包括 6 个普通 IO&#xff0c;3 对串口&#xff0c;一个 SPI。TH1520 SOC 具有4个GPIO bank&#xff0c;每个bank最大有32个IO&#xff1a;  …...

HTML项目一键打包工具:HTML2EXE 最新版

HTML2EXE 工具可以一键打包生成EXE可执行文件。可以打包任意HTML项目或者是一个网址为单个EXE文件&#xff0c;直接打开即可运行。支持KRPano全景VR项目、WebGL游戏项目、视频播放、,课件打包、网址打包等。 下载地址&#xff1a; 最新版HTML2EXE首次发布下载地址 一、功能特点…...

BGP配置华为——路径优选验证

实验拓扑 实验要求 实现通过修改AS-Path属性来影响路径选择实现通过修改Local_Preference属性来影响路径选择实现通过修改MED属性来影响路径选择实现通过修改preferred-value属性来影响路径选择 实验配置与效果 1.改名与IP配置 2.as300配置OSPF R3已经学到R2和R4的路由 3.…...

深度学习基础--ResNet网络的讲解,ResNet50的复现(pytorch)以及用复现的ResNet50做鸟类图像分类

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 如果说最经典的神经网络&#xff0c;ResNet肯定是一个&#xff0c;这篇文章是本人学习ResNet的学习笔记&#xff0c;并且用pytorch复现了ResNet50&…...

TMDS视频编解码算法

因为使用的是DDR进行传输&#xff0c;即双倍频率采样&#xff0c;故时钟只用是并行数据数据的5倍&#xff0c;而不是10倍。 TMDS算法流程&#xff1a; 视频编码TMDS算法流程实现&#xff1a; timescale 1 ps / 1ps //DVI编码通常用于视频传输&#xff0c;将并行数据转换为适合…...

深度解析SmartGBD助力Android音视频数据接入GB28181平台

在当今数字化时代&#xff0c;视频监控与音视频通信技术在各行各业的应用愈发广泛。GB28181协议作为中国国家标准&#xff0c;为视频监控设备的互联互通提供了规范&#xff0c;但在实际应用中&#xff0c;许多Android终端设备并不具备国标音视频能力&#xff0c;这限制了其在相…...

前端兼容处理接口返回的文件流或json数据

参考文档&#xff1a;JavaScript | MDN 参考链接&#xff1a;Blob格式转json格式&#xff0c;拿到后端返回的json数据_blob转json-CSDN博客 参考链接&#xff1a;https://juejin.cn/post/7117939029567340557 场景&#xff1a;导入上传文件&#xff0c;导入成功&#xff0c;…...

Eclipse 透视图 (Perspective)

Eclipse 透视图 (Perspective) Eclipse 是一款强大的集成开发环境(IDE),广泛应用于 Java 开发领域。其中,透视图(Perspective)是 Eclipse 中的一个核心概念,它将不同的工具和视图组合在一起,以便开发者能够更高效地完成特定的开发任务。本文将详细介绍 Eclipse 透视图…...

嵌入式硬件篇---滤波器

文章目录 前言一、模拟电子技术中的滤波器1. 基本概念功能实现方式 2. 分类按频率响应低通滤波器高通滤波器带通滤波器带阻滤波器 按实现方式无源滤波器有源滤波器 3. 设计方法巴特沃斯滤波器&#xff08;Butterworth&#xff09;切比雪夫滤波器&#xff08;Chebyshev&#xff…...

从零到一学习c++(基础篇--筑基期十一-类)

从零到一学习C&#xff08;基础篇&#xff09; 作者&#xff1a;羡鱼肘子 温馨提示1&#xff1a;本篇是记录我的学习经历&#xff0c;会有不少片面的认知&#xff0c;万分期待您的指正。 温馨提示2&#xff1a;本篇会尽量用更加通俗的语言介绍c的基础&#xff0c;用通俗的语言去…...

Java基础常见的面试题(易错!!)

面试题一&#xff1a;为什么 Java 不支持多继承 Java 不支持多继承主要是为避免 “菱形继承问题”&#xff08;又称 “钻石问题”&#xff09;&#xff0c;即一个子类从多个父类继承到同名方法或属性时&#xff0c;编译器无法确定该调用哪个父类的成员。同时&#xff0c;多继承…...

DPVS-2:单臂负载均衡测试

上一篇编译安装了DPVS&#xff0c;这一篇开启DPVS的负载均衡测试 &#xff1a; 单臂 FULL NAT模式 拓扑-单臂 单臂模式 DPVS 单独物理机 CLINET&#xff0c;和两个RS都是另一个物理机的虚拟机&#xff0c;它们网卡都绑定在一个桥上br0 &#xff0c; 二层互通。 启动DPVS …...

C#中提供的多种集合类以及适用场景

在 C# 中&#xff0c;有多种集合类可供使用&#xff0c;它们分别适用于不同的场景,部分代码示例提供了LeetCode相关的代码应用。 1. 数组&#xff08;Array&#xff09; 特点 固定大小&#xff1a;在创建数组时需要指定其长度&#xff0c;之后无法动态改变。连续存储&#xf…...

【蓝桥杯集训·每日一题2025】 AcWing 6135. 奶牛体检 python

6135. 奶牛体检 Week 1 2月21日 农夫约翰的 N N N 头奶牛站成一行&#xff0c;奶牛 1 1 1 在队伍的最前面&#xff0c;奶牛 N N N 在队伍的最后面。 农夫约翰的奶牛也有许多不同的品种。 他用从 1 1 1 到 N N N 的整数来表示每一品种。 队伍从前到后第 i i i 头奶牛的…...

【为什么用pg数据库用 != null 过滤不出null值】

为什么用pg数据库用 ! null 过滤不出null值 1. NULL 的特殊性质2. 为什么 ! null 无效3. 正确的过滤 NULL 的方式示例 4. 为什么 IS NULL 和 IS NOT NULL 有效5. 示例对比6. 总结 在 PostgreSQL 中&#xff0c;使用 ! null 过滤不出 NULL 值的原因与 SQL 标准中 NULL 的特殊性质…...

Classic Control Theory | 12 Real Poles or Zeros (第12课笔记-中文版)

笔记链接&#xff1a;https://m.tb.cn/h.Tt876SW?tkQaITejKxnFLhttps://m.tb.cn/h.Tt876SW?tkQaITejKxnFL...

Kubernetes开发环境minikube | 开发部署MySQL单节点应用

minikube是一个主要用于开发与测试Kubernetes应用的运行环境 本文主要描述在minikube运行环境中部署MySQL单节点应用 minikube start --force kubectl get nodes 如上所示&#xff0c;启动minikube单节点运行环境 minikube ssh docker pull 如上所示&#xff0c;从MySQL官…...

大厂数据仓库数仓建模面试题及参考答案

目录 什么是数据仓库,和数据库有什么区别? 数据仓库的基本原理是什么? 数据仓库架构是怎样的? 数据仓库分层(层级划分),每层做什么?分层的好处是什么?数据分层是根据什么?数仓分层的原则与思路是什么? 数仓建模常用模型有哪些?区别、优缺点是什么?星型模型和雪…...

腾讯SQL面试题解析:如何找出连续5天涨幅超过5%的股票

腾讯SQL面试题解析:如何找出连续5天涨幅超过5%的股票 作者:某七年数据开发工程师 | 2025年02月23日 关键词:SQL窗口函数、连续问题、股票分析、腾讯面试题 一、问题背景与难点拆解 在股票量化分析场景中,"连续N天满足条件"是高频面试题类型。本题要求在单表stoc…...

安装可视化jar包部署平台JarManage

一、下载 下载地址&#xff1a;JarManage 发行版 - Gitee.com &#x1f692; 下载 最新发行版 下载zip的里面linux和windows版本都有 二、运行 上传到服务器&#xff0c;解压进入目录 &#x1f69a; 执行java -jar jarmanage-depoly.jar 命令运行 java -jar jarmanage-dep…...

基于数据可视化+SpringBoot+安卓端的数字化OA公司管理平台设计和实现

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…...

输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路

详细前端代码写于上一篇&#xff1a;输入搜索、分组展示选项、下拉选取&#xff0c;el-select 实现&#xff1a;即输入关键字检索&#xff0c;返回分组选项&#xff0c;选取跳转到相应内容页 —— VUE项目-全局模糊检索 【效果图】&#xff1a;分组展示选项 >【去界面操作体…...

性能巅峰对决:Rust vs C++ —— 速度、安全与权衡的艺术

??关注&#xff0c;带你探索Java的奥秘&#xff01;?? ??超萌技术攻略&#xff0c;轻松晋级编程高手&#xff01;?? ??技术宝库已备好&#xff0c;就等你来挖掘&#xff01;?? ??订阅&#xff0c;智趣学习不孤单&#xff01;?? ??即刻启航&#xff0c;编…...

unity学习53:UI的子容器:面板panel

目录 1 UI的最底层容器&#xff1a;canvas 1.1 UI的最底层容器&#xff1a;canvas 1.2 UI的合理结构 2 UI的子容器&#xff1a;面板panel 2.1 创建panel 2.2 面板的本质&#xff1a; image &#xff0c;就是一个透明的图片&#xff0c;1个空容器 3 面板的属性 4 面板的…...

4-知识图谱的抽取与构建-4_2实体识别与分类

&#x1f31f; 知识图谱的实体识别与分类&#x1f525; &#x1f50d; 什么是实体识别与分类&#xff1f; 实体识别&#xff08;Entity Recognition&#xff09;是从文本中提取出具体的事物&#xff0c;如人名、地名、组织名等。分类&#xff08;Entity Classification&#x…...

elasticsearch在windows上的配置

写在最前面&#xff1a; 上资源 第一步 解压&#xff1a; 第二步 配置两个环境变量 第三步 如果是其他资源需要将标蓝的文件中的内容加一句 xpack.security.enabled: false 不同版本的yaml文件可能配置不同&#xff0c;末尾加这个 xpack.security.enabled: true打开bin目…...

详解分布式ID实践

引言 分布式ID&#xff0c;所谓的分布式ID&#xff0c;就是针对整个系统而言&#xff0c;任何时刻获取一个ID&#xff0c;无论系统处于何种情况&#xff0c;该值不会与之前产生的值重复&#xff0c;之后获取分布式ID时&#xff0c;也不会再获取到与其相同的值&#xff0c;它是…...

如何在 Vue 项目中为 `el-pagination` 设置中文

文章目录 前言1. 安装 Element Plus2. 引入中文语言包3. 配置中文语言环境4. 使用 el-pagination 组件5. 确保其他组件支持中文6. 语言切换&#xff08;可选&#xff09;总结 前言 在 Vue 项目中&#xff0c;Element Plus 是一个流行的 UI 组件库&#xff0c;它提供了许多常用…...

PostgreSQL:更新字段慢

目录标题 PostgreSQL 慢查询优化与 pg_stat_statements 使用1. 启用慢查询日志2. 使用 pg_stat_statements 扩展收集查询统计信息3. 查找执行时间较长的查询4. 分析慢查询的执行计划5. 优化查询6. 检查并发连接和系统资源7. 进一步优化8. 查看某条SQL1. **如何生成 query_id**2…...