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 文件中。