📑 目录
- [1. 绘图](#1. 绘图)
- [1.1 基本概念](#1.1 基本概念)
- [1.2 绘制各种形状](#1.2 绘制各种形状)
- [1.3 绘制图片](#1.3 绘制图片)
- [1.4 其他设置](#1.4 其他设置)
- [1.5 特殊的绘图设备](#1.5 特殊的绘图设备)
- [2. 小总结](#2. 小总结)
- [3. 经典面试题](#3. 经典面试题)
1. 绘图
1.1 基本概念
虽然 Qt 已经内置了很多的控件,但是不能保证现有控件就可以应对所有场景。很多时候我们需要更强的"自定制"能力。
Qt 提供了画图相关的 API,可以允许我们在窗口上绘制任意的图形形状,来完成更复杂的界面设计。
💡 所谓的"控件",本质上也是通过画图的方式画上去的。
画图 API 和控件之间的关系,可以类比成机器指令和高级语言之间的关系。控件是对画图 API 的进一步封装;画图 API 是控件的底层实现。
绘图 API 核心类
| 类 | 说明 |
|---|---|
QPainter |
"绘画者"或者"画家"。用来绘图的对象,提供了一系列 drawXXX 方法,可以允许我们绘制各种图形。 |
QPaintDevice |
"画板"。描述了 QPainter 把图形画到哪个对象上。像咱们之前用过的 QWidget 也是一种 QPaintDevice(QWidget 是 QPaintDevice 的子类)。 |
QPen |
"画笔"。描述了 QPainter 画出来的线是什么样的。 |
QBrush |
"画刷"。描述了 QPainter 填充一个区域是什么样的。 |
绘图 API 的使用,一般不会在 QWidget 的构造函数中使用,而是要放到 paintEvent 事件中。
💡 关于 paintEvent
paintEvent 会在以下情况下被触发:
- 控件首次创建。
- 控件被遮挡,再解除遮挡。
- 窗口最小化,再恢复。
- 控件大小发生变化时。
- 主动调用
repaint()或者update()方法。(这两个方法都是QWidget的方法)。 - ...
因此,如果把绘图 API 放到构造函数中调用,那么一旦出现上述的情况,界面的绘制效果就无法确保符合预期了。
1.2 绘制各种形状
1.2.1 绘制线段
示例 1:
cpp
void drawLine(const QPoint &p1, const QPoint &p2);
参数:
p1:绘制起点坐标p2:绘制终点坐标
1、在 widget.h 头文件中声明绘图事件;
cpp
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//声明会话事件
void paintEvent(QPaintEvent *event) override;
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
2、在 widget.cpp 文件中重写 paintEvent() 方法;
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化Painter对象
//参数this表示:在当前窗口中绘图,也就是绘图设备(画板)是QWidget
QPainter painter(this);
//画一条线
painter.drawLine(QPoint(20,50),QPoint(200,50));
}
实现效果如下:

示例 2:
cpp
void drawLine(int x1, int y1, int x2, int y2);
参数:
x1, y1:绘制起点坐标x2, y2:绘制终点坐标
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化Painter对象
//参数this表示:在当前窗口中绘图,也就是绘图设备(画板)是QWidget
QPainter painter(this);
//画一条线
painter.drawLine(QPoint(20,50),QPoint(200,50));
//画一条线的另一种方法
painter.drawLine(20,100,200,100);
}

1.2.2 绘制矩形
cpp
void QPainter::drawRect(int x, int y, int width, int height);
参数:
x:窗口横坐标;y:窗口纵坐标;width:所绘制矩形的宽度;height:所绘制矩形的高度;
📚 此处的窗口的横纵坐标指的是矩形左上角的坐标。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化Painter对象
//参数this表示:在当前窗口中绘图,也就是绘图设备(画板)是QWidget
QPainter painter(this);
//绘制矩形
painter.drawRect(50,50,100,50);
}

1.2.3 绘制圆形
cpp
void QPainter::drawEllipse(const QPoint ¢er, int rx, int ry)
参数:
center:中心点坐标rx:x方向上的半径ry:y方向上的半径
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化Painter对象
//参数this表示:在当前窗口中绘图,也就是绘图设备(画板)是QWidget
QPainter painter(this);
//绘制椭圆
painter.drawEllipse(QPoint(150,150),50,50);
}
实现效果:

1.2.4 绘制文本
QPainter 类中不仅提供了绘制图形的功能,还可以使用 QPainter::drawText() 函数来绘制文字,也可以使用 QPainter::setFont() 设置字体等信息。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化Painter对象
//参数this表示:在当前窗口中绘图,也就是绘图设备(画板)是QWidget
QPainter painter(this);
//1.设置字体
QFont font("华文行楷",20);
painter.setFont(font);
//2.设置画笔颜色
painter.setPen(Qt::red);
//3.绘制文字
painter.drawText(QRect(100,200,600,150),"为中华之崛起而读书");
}
实现效果如下:

1.2.5 设置画笔
QPainter 在绘制时,是有一个默认的画笔的。在使用时也可以自定义画笔。在 Qt 中,QPen 类中定义了 QPainter 应该如何绘制形状、线条和轮廓。同时通过 QPen 类可以设置画笔的线宽、颜色、样式、画刷等。
画笔的颜色可以在实例化画笔对象时进行设置,画笔的宽度是通过 setWidth() 方法进行设置,画笔的风格是通过 setStyle() 方法进行设置,设置画刷主要是通过 setBrush() 方法。
- 设置画笔颜色:
QPen::QPen(const QColor &color)------ 画笔的颜色主要是通过QColor类设置; - 设置画笔宽度:
void QPen::setWidth(int width) - 设置画笔风格:
void QPen::setStyle(Qt::PenStyle style)
画笔的风格有:

示例:画笔的使用
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
//2.设置画笔
QPen pen(QColor(0,255,0));
//3.设置画笔宽度
pen.setWidth(3);
//4.设置画笔风格
pen.setStyle(Qt::DashLine);
//5.让画家使用风格
painter.setPen(pen);
//6.绘制圆
painter.drawEllipse(QPoint(150,150),80,50);
}
实现效果如下:

1.2.6 设置画刷
在 Qt 中,画刷是使用 QBrush 类来描述,画刷大多用于填充。QBrush 定义了 QPainter 的填充模式,具有样式、颜色、渐变以及纹理等属性。
画刷的格式中定义了填充的样式,使用 Qt::BrushStyle 枚举,默认值是 Qt::NoBrush,也就是不进行任何填充。可以通过 Qt 助手查找画刷的格式。
设置画刷主要通过 void QPen::setBrush(const QBrush &brush) 方法,其参数为画刷的格式。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
//2.设置画笔
QPen pen(QColor(255,0,0));
//3.设置画笔宽度
pen.setWidth(3);
//4.设置画笔风格
pen.setStyle(Qt::DashLine);
//5.让画家使用风格
painter.setPen(pen);
//6.设置画刷 给封闭图形填充颜色
QBrush brush(Qt::cyan);
//7.设置画刷风格
brush.setStyle(Qt::Dense1Pattern);
//8.让画家使用画刷
painter.setBrush(brush);
//9.绘制圆
painter.drawEllipse(QPoint(150,150),50,50);
}
实现效果:

1.3 绘制图片
Qt 提供了四个类来处理图像数据:QImage、QPixmap、QBitmap 和 QPicture,它们都是常用的绘图设备。
QImage 主要用来进行 I/O 处理,它对 I/O 处理操作进行了优化,而且可以用来直接访问和操作像素;
QPixmap 主要用来在屏幕上显示图像,它对在屏幕上显示图像进行了优化;
QBitmap 是 QPixmap 的子类,用来处理颜色深度为 1 的图像,即只能显示黑白两种颜色;
QPicture 用来记录并重演 QPainter 命令。这一节只讲解 QPixmap。
1.3.1 绘制简单图片
- 新建 Qt 项目,基类选择
QWidget,项目名称为QPainter。在widget.h头文件中声明绘画事件;
cpp
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//声明会话事件
void paintEvent(QPaintEvent *event) override;
private:
Ui::Widget *ui;
};
-
添加资源文件;
首先准备一些图片资源文件,并将这些图片资源文件放在同一个文件夹中,将该文件夹复制到本项目中;

-
选中项目文件,鼠标右键 ---> add new...

-
点击 "add new..." 之后,出现如下界面:

-
选择 "Choose..." 之后,给资源文件命名;

-
点击 "下一步",出现如下界面,点击 "完成";

-
给资源文件添加前缀,并将资源文件添加至项目中;

-
将所有的资源文件添加到项目中,方便后续使用;

-
点击 "构建并运行" 按钮,将资源文件添加到项目中;
-
在
widget.cpp文件中实现画图片功能;
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
//2.绘制图片
painter.drawPixmap(0,0,QPixmap(":/picture/panda.png"));
}
实现效果如下:

1.3.2 平移图片
平移图片实际是通过改变坐标来实现。QPainter 类中提供了 translate() 函数来实现坐标原点的改变。如下示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
//2.将画板的左上角坐标移动到(100,100)处,实现移动图像
painter.translate(100,100);
//3.绘制图片
painter.drawPixmap(0,0,QPixmap(":/picture/panda.png"));
实现效果如下:

1.3.3 缩放图片
在 Qt 中,图片的放大和缩小可以使用 QPainter 类中的 drawPixmap() 函数来实现。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化画家对象
QPainter painter(this);
//绘制图片
painter.drawPixmap(0,0,QPixmap(":/picture/panda.png"));
//以(300,400)点开始画图,图片尺寸变为 50*60
painter.drawPixmap(900,900,100,80,QPixmap(":/picture/panda.png"));
}
实现效果如下:

1.3.4 旋转图片
图片的旋转使用的是 QPainter 类中的 rotate() 函数,它默认是以原点为中心进行旋转的。如果要改变旋转的中心,可以使用 translate() 函数完成。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//实例化画家对象
QPainter painter(this);
// 图片的中心作为旋转中心
painter.translate(200,300);
painter.rotate(90);//顺时针旋转90度
painter.translate(-200,-300);//使原点复原
//以(300,400)点开始画图,图片尺寸变为50*60
painter.drawPixmap(0,0,300,280,QPixmap(":/picture/panda.png"));
}
实现效果如下:

1.4 其他设置
1.4.1 移动画家位置
有时候在绘制多个图形时,想使用同一坐标位置,那么绘制出来的图形肯定会重合,此时,可以通过移动画家的位置来使图形不发生重合。
示例 1:未移动画家位置
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
#include<QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
//使用同一坐标,此时的两个圆会重合,绘制出来的只有一个圆
painter.drawEllipse(QPoint(100,200),50,50);
painter.drawEllipse(QPoint(100,200),50,50);
}
实现效果如下:

示例 2:移动画家位置
- 使用
translate移动画家所在位置。
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
#include<QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
painter.drawEllipse(QPoint(100,200),50,50);
//让画家移动
painter.translate(200,0);
painter.drawEllipse(QPoint(100,200),50,50);
}
实现效果如下:

1.4.2 保存/加载画家的状态
在绘制图形的过程中,可以通过 save() 函数来保存画家的状态,使用 restore() 函数还原画家状态。
save() 函数原型如下:
cpp
void QPainter::save();
restore() 函数原型如下:
cpp
void QPainter::restore();
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPixmap>
#include<QPoint>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
//1.实例化画家对象
QPainter painter(this);
painter.drawEllipse(QPoint(100,200),50,50);//画图
painter.translate(200,0);//让画家移动
painter.save();//保存画家状态
painter.drawEllipse(QPoint(100,200),50,50);//画图
painter.translate(200,0);//让画家移动
painter.restore();//还原画家状态
painter.drawEllipse(QPoint(100,200),50,50);
}
实现效果如下:

📚 说明:
上述示例中,在画第三个圆之前,由于还原了画家的状态,所以此时画家的位置坐标会移动到画家状态保存的地方,所以在绘制第三个圆的位置时实际是和第二个圆发生了重叠。
1.5 特殊的绘图设备
前面的代码中我们是使用 QWidget 作为绘图设备。在 Qt 中还存在下列三个比较特殊的绘图设备。此处我们也简要介绍。
QPixmap用于在显示器上显示图片。QImage用于对图片进行像素级修改。QPicture用于对QPainter的一系列操作进行存档。
1.5.1 QPixmap
QPixmap 核心特性:
- 使用
QPainter直接在上面进行绘制图形。 - 通过文件路径加载并显示图片。
- 搭配
QPainter的drawPixmap()函数,可以把这个图片绘制到一个QLabel、QPushButton等控件上。 - 和系统/显示设备强相关,不同系统/显示设备下,
QPixmap的显示可能会有所差别。
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPixmap>
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//Pixmap绘图设备,绘图设备尺寸为:500*500
QPixmap pix(500,500);
QPainter painter(&pix);//实例化画家对象
painter.setPen(Qt::blue);//设置画笔颜色
painter.drawEllipse(QPoint(100,100),100,100);
//保存绘制的图片
pix.save("D:\\Qt\\code\\Paint\\pixmap");
}
Widget::~Widget()
{
delete ui;
}

1.5.2 QImage
QImage 的核心特性:
- 使用
QPainter直接在上面进行绘制图形。 - 通过文件路径加载并显示图片。
- 能够针对图片进行像素级别的操作(操作某个指定的像素)。
- 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示。
代码示例:QImage 作为绘图设备的使用
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPixmap>
#include<QPainter>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//绘图设备的大小为500*500,绘图格式为:QImage::Format_RGB32
QImage img(500,500,QImage::Format_RGB32);
img.fill(Qt::white);//填充色为白色,默认为黑色
QPainter painter(&img);//声明画家,画图设备为img
painter.setPen(QPen(Qt::cyan));//设置画笔颜色为蓝绿色(青色)
painter.drawEllipse(QPoint(200,200),100,100);//画图
img.save("D:\\Qt\\code\\Paint\\pixmap\\img.png");
}
Widget::~Widget()
{
delete ui;
}

代码示例:QImage 绘图时对像素的修改
-
新建 Qt 项目,添加图片资源文件到项目中;如下图示:
-
在
widget.h头文件中声明绘图事件;
cpp
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
//声明绘图事件
void paintEvent(QPaintEvent* event);
private:
Ui::Widget *ui;
};
- 在
widget.cpp文件中重写绘图事件,使用QImage对图片像素进行修改;
- 通过
setPixel设置某个像素的颜色值。 - 使用
qRgb表示一个具体的颜色。
cpp
void Widget::paintEvent(QPaintEvent *event)
{
//实例化画家对象
QPainter painter(this);
QImage img;
img.load("/pix.png");//加载图片
//修改像素点
for(int i = 100;i < 200;i++)
{
for(int j = 100;j < 200;j++)
{
QRgb rgb = qRgb(255,0,0);
img.setPixel(i,j,rgb);
}
}
painter.drawImage(0,0,img);
}
1.5.3 QPicture
QPicture 核心特性:
- 使用
QPainter直接在上面进行绘制图形。 - 通过文件路径加载并显示图片。
- 能够记录
QPainter的操作步骤。 - 独立于硬件的绘制系统,能够在不同系统之上提供一致的显示。
注意:
QPicture 加载的必须是自身的存档文件,而不能是任意的 png,jpg 等图片文件。
💡 QPicture 类似于很多游戏的 Replay 功能。
例如像 war3 这样的经典游戏,即使是一场 60 分钟的膀胱局,生成的 replay 文件,也不过几百个 KB。
此处的 Replay 功能并非是把整个游戏画面都录制保存下来,而是记录了地图中发生的所有事件(地图元素,玩家单位操作,中立生物行为等...)。
当回放 Replay 的时候其实就是把上述记录的事件再一条一条的执行一遍即可还原之前的游戏场景了。
如果要记录下 QPainter 的命令,首先要使用 QPainter::begin() 函数,将 QPicture 实例作为参数传递进去,以便告诉系统开始记录,记录完毕后使用 QPainter::end() 命令终止。如下示例:
示例:
cpp
#include "widget.h"
#include "ui_widget.h"
#include<QPainter>
#include<QPicture>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPicture pic;
QPainter painter;
painter.begin(&pic);//开始往pic绘图设备上绘图
painter.setPen(QPen(Qt::red));//设置画笔颜色为红色
painter.drawEllipse(QPoint(200,200),100,100);
painter.end();//结束绘画
pic.save("D:\\Qt\\code\\Paint\\picture\\pic.pic");
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QPicture pic;
pic.load("D:\\Qt\\code\\Paint\\picture\\pic.pic");
painter.drawPicture(0,0,pic);
}
实现效果:

通过 QPicture 重现绘图指令后,实现的效果如下:

2. 小总结
本章我们系统学习了 Qt 绘图相关的核心知识,从最基础的 QPainter、QPaintDevice、QPen、QBrush 四大核心类,到各种基本图形的绘制(线段、矩形、圆形、文本),再到画笔和画刷的详细配置,最后深入探讨了图片的绘制与变换(平移、缩放、旋转)以及三种特殊绘图设备(QPixmap、QImage、QPicture)的适用场景。
核心要点回顾:
- 🎨 绘图入口 :绘图代码必须放在
paintEvent中,而不是构造函数里,这样才能保证界面在各种情况下都能正确重绘。 - 🖌️ 画笔(QPen):控制线条的颜色、宽度和风格,是绘制轮廓的关键。
- 🖍️ 画刷(QBrush):控制填充区域的样式,支持纯色、渐变、纹理等多种填充模式。
- 🖼️ 图片处理三兄弟 :
QPixmap负责屏幕显示(与硬件相关)、QImage负责像素级操作(跨平台一致)、QPicture负责记录和重演绘图指令(类似游戏 Replay)。 - 🔄 画家状态管理 :
save()和restore()可以保存/恢复画家的位置和状态,避免复杂的坐标计算。
3. 经典面试题
Q1:QPainter、QPaintDevice、QPen、QBrush 四者的关系是什么?
A1:QPainter 是"画家",负责执行具体的绘制操作,提供了一系列 drawXXX 方法;QPaintDevice 是"画板",指定了 QPainter 将图形绘制到哪个对象上(如 QWidget、QPixmap、QImage 等);QPen 是"画笔",决定了绘制线条的颜色、宽度和风格;QBrush 是"画刷",决定了填充区域的颜色和样式。简单来说,QPainter 拿着 QPen 和 QBrush 在 QPaintDevice 上作画。
Q2:为什么绘图代码要放在 paintEvent 中,而不是构造函数里?
A2:因为 paintEvent 会在多种情况下被自动触发,包括:控件首次创建、被遮挡后重新显示、窗口最小化后恢复、控件大小改变、主动调用 repaint() 或 update() 等。如果放在构造函数中,一旦出现上述情况,界面就无法正确重绘,导致显示异常。放在 paintEvent 中则可以确保任何时刻界面都能被正确绘制。
Q3:QPixmap、QImage、QPicture 三者有什么区别?各自的应用场景是什么?
A3:三者都是绘图设备,但侧重点不同:
QPixmap:针对屏幕显示做了优化,主要用于在界面上快速显示图片,但与具体显示设备相关,不同系统下显示效果可能有差异。QImage:针对 I/O 和像素操作做了优化,可以独立于硬件提供一致的显示效果,适合需要对图片进行像素级修改的场景(如通过setPixel修改某个像素的颜色)。QPicture:用于记录和重演QPainter的绘图指令,类似于游戏的 Replay 功能,文件体积小,回放时逐条执行记录的指令即可还原场景。注意它只能加载自身的存档文件,不能加载任意图片格式。
Q4:如何实现图片的旋转?如果要绕指定中心点旋转该怎么做?
A4:图片旋转使用 QPainter::rotate() 函数,默认以原点(0,0)为中心旋转。如果要绕指定中心点旋转,需要先调用 translate() 将坐标原点平移到目标中心点,再调用 rotate() 进行旋转,绘制完成后再用 translate() 平移回来(或使用 save()/restore() 保存和恢复画家状态)。