QT:paintEvent、QPainter、QPaintDevice

news/2025/2/26 4:44:58

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 对象,作为 QPaintDevice
        painter.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 文件中。

在这里插入图片描述


http://www.niftyadmin.cn/n/5867160.html

相关文章

C语言中的文件和文件操作

文件操作 一、文件的打开和关闭二、文件的顺序读写fgetc和fputcfgets和fputsfscanf和fprintfsscanf和sprintffread和fwrite 三、文件的随机读写1.fseek2.ftell3.rewind 四、补充1.文件读取结束的判定2.文件缓冲区 一、文件的打开和关闭 流和标准流 流&#xff1a;想象为流淌着…

面试八股文--数据库基础知识总结(2) MySQL

本文介绍关于MySQL的相关面试知识 一、关系型数据库 1、定义 关系型数据库&#xff08;Relational Database&#xff09;是一种基于关系模型的数据库管理系统&#xff08;DBMS&#xff09;&#xff0c;它将数据存储在表格&#xff08;表&#xff09;中&#xff0c;并通过表格…

Ubuntu DeepSeek磁盘空间不够解决办法

标签&#xff1a; Ubuntu&#xff1b; DeepSeek磁盘空间不够解决办法&#xff1b;Ubuntu 22, DeepSeek R1 671 B, solution for Insufficient Disk Space 问题&#xff1a;Ubuntu 22&#xff0c; DeepSeek R1 671B 磁盘空间不够解决办法 Ubuntu 22.04操作系统&#xff0c;台式…

基于keepalived实现haproxy高可用站点

Keepalived起初是为LVS设计的&#xff0c;专门用来监控集群系统中各个服务节点的状态&#xff0c;后来有加入VRRP的功 能&#xff0c;VRRP是Virtual Router Redundancy protocol&#xff08;虚拟路由器冗余协议&#xff09;的缩写&#xff0c;VRRP出现的目的就 是为了解决静态路…

基于javaweb的SpringBoot社区维修平台设计和实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论…

图解前馈神经网络(FNN)

目录 ​编辑 1.前馈神经网络介绍 2.网络结构 3.模型工作示例 4.总结 1.前馈神经网络介绍 前馈神经网络&#xff08;Feedforward Neural Network&#xff0c;FNN&#xff09;是一种最简单、最经典的神经网络结构&#xff0c;它是人工神经网络的基础形式之一。 前馈神经网络…

忽略Git文件的修改,让它不被提交

使用Git托管的工程中&#xff0c;经常有这样的需求&#xff0c;希望文件只是本地修改&#xff0c;不提交到服务端。 如果仅仅是本地存在的文件&#xff0c;我们可以通过.gitignore配置避免文件被提交。 有的时候文件是由git托管的&#xff0c;但是我们希望只在本地修改&#…

运行 Rancher 的建议

运行在多个节点上的多个 Rancher 实例确保了单节点环境无法实现的高可用性&#xff0c;所以在生产环境或者一些很重要的环境中部署 Rancher 时&#xff0c;应该使用至少有三个节点的高可用 Kubernetes 集群&#xff0c;并在这个集群上面安装 Rancher。 在专用的集群上运行 Ran…