文章目录
-
- [2. 绘图](#2. 绘图)
-
- [2.1 基本概念](#2.1 基本概念)
- [2.2 绘制各种形状](#2.2 绘制各种形状)
-
- [2.2.1 绘制线段](#2.2.1 绘制线段)
- [2.2.2 绘制矩形](#2.2.2 绘制矩形)
- [2.2.3 绘制圆形](#2.2.3 绘制圆形)
- [2.2.4 绘制文本](#2.2.4 绘制文本)
- [2.2.5 设置画笔](#2.2.5 设置画笔)
- [2.2.6 设置画刷](#2.2.6 设置画刷)
- [2.3 绘制图片](#2.3 绘制图片)
-
- [2.3.1 绘制简单图片](#2.3.1 绘制简单图片)
- [2.3.2 平移图片](#2.3.2 平移图片)
- [2.3.3 缩放图片](#2.3.3 缩放图片)
- [2.3.4 旋转图片](#2.3.4 旋转图片)
- [2.4 其他设置](#2.4 其他设置)
-
- [2.4.1 移动位置](#2.4.1 移动位置)
- [2.4.2 保存/加载状态](#2.4.2 保存/加载状态)
- [2.5 其他绘图类](#2.5 其他绘图类)
-
- [2.5.1 QPixmap](#2.5.1 QPixmap)
- [2.5.2 QImage](#2.5.2 QImage)
- [2.5.3 QPicture](#2.5.3 QPicture)
2. 绘图
2.1 基本概念
虽然 Qt 已经内置了很多的控件, 但是不能保证现有控件就可以应对所有场景,Qt 提供了画图相关的 API, 允许在窗⼝上绘制任意的图形形状, 来完成更复杂的界⾯设计。
核心类:
| 类 | 说明 |
|---|---|
| QPainter | 画家,提供 drawXXX 方法绘制图形 |
| QPaintDevice | 画板(如 QWidget),指定绘制目标 |
| QPen | 画笔,定义线条样式(颜色、宽度、风格) |
| QBrush | 画刷,定义填充样式(颜色、渐变、纹理) |
5类重绘触发的场景:
-
控件首次创建时
QWidget完成构造并进入显示流程(
show()/exec()触发)时,Qt事件循环会向该控件派发QPaintEvent事件,驱动paintEvent(QPaintEvent*)虚函数执行。 -
控件被遮挡后解除遮挡
当QWidget的部分/全部区域被其他顶层窗口/子控件遮挡时,该区域会被Qt标记为「无效区域(Invalid Region)」;遮挡解除后,窗口系统(Windows/X11/macOS)会通知Qt更新无效区域,Qt随即为该区域派发
QPaintEvent(仅重绘无效区域,而非全量)。 -
窗口被最小化后还原
窗口最小化时,其对应的系统窗口句柄(HWND/Window ID)会脱离屏幕显示链表,系统会释放该窗口的显存缓冲区(back buffer);窗口还原时,窗口句柄重新关联显示设备,Qt会触发全量QPaintEvent 以重建窗口视觉内容。
-
控件大小发生改变时
QWidget的
resize()/setGeometry()等操作导致尺寸/位置变更时,Qt会标记控件整体为无效区域,并派发QPaintEvent。 -
主动调用repaint()/update()触发
repaint():立即向事件循环派发QPaintEvent,强制同步重绘;若在非UI线程调用,可能引发线程安全问题(Qt绘图仅允许在主线程执行)。update():标记控件为无效区域,由Qt事件循环在下一次迭代时合并多个无效区域 ,异步派发QPaintEvent;避免频繁重绘导致的性能损耗,是推荐的手动触发方式。
- 初始绘制逻辑必须在
paintEvent内实现,才能在控件首次渲染时生效。
2.2 绘制各种形状
2.2.1 绘制线段
cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawLine(QPoint(20,20), QPoint(200,20)); // 两点绘制
painter.drawLine(20, 100, 200, 100); // 坐标绘制
}

2.2.2 绘制矩形
cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawRect(20,20,100,50); // (x,y,宽度,高度)
}

2.2.3 绘制圆形
cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawEllipse(QPoint(50, 50), 50, 50); // (中心点, x半径, y半径)
painter.drawEllipse(0, 0, 100, 100); // 中心点(100,100),x/y直径100 → 半径50r
}

2.2.4 绘制文本
cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setFont(QFont("鸿蒙黑体",24));//字体名称,字号
painter.setPen(Qt::black);//设置画笔颜色为红色
painter.drawText(QRect(100,200,600,150),"别感冒!");//左上方坐标,宽度,高度,内容
// x: 文字基线(Baseline)的水平起始坐标(距离控件左边缘0像素)
// y: 文字基线(Baseline)的垂直坐标(距离控件上边缘100像素)【重点:不是文字顶部/底部】
// text: 要绘制的文本内容
painter.drawText(10, 100, "hello world");
}

2.2.5 设置画笔
常用属性与设置方法:
-
颜色(Color)
- 构造时指定:
QPen pen(Qt::red); - 后期修改:
pen.setColor(QColor(0, 128, 255));
- 构造时指定:
-
宽度(Width)
- 整数宽度:
pen.setWidth(3);(默认值为1) - 浮点宽度:
pen.setWidthF(2.5);(支持更精细的宽度控制)
- 整数宽度:
-
线条风格(PenStyle)
- 常用取值 :
pen.setStyle(Qt::DashDotLine);
- 常用取值 :
| 枚举值 | 效果 |
|---|---|
Qt::NoPen |
无轮廓(只填充图形内部) |
Qt::SolidLine |
实线(默认) |
Qt::DashLine |
虚线(短横线间隔) |
Qt::DotLine |
点线(点间隔) |
Qt::DashDotLine |
点划线(横线+点间隔) |
Qt::DashDotDotLine |
双点划线(横线+两点间隔) |
Qt::CustomDashLine |
自定义虚线样式 |
-
端点样式(PenCapStyle)
Qt::FlatCap:平端(默认,端点与线条边缘齐平)Qt::SquareCap:方端(端点超出线条边缘半个宽度)Qt::RoundCap:圆端(端点为半圆形)
-
连接样式(PenJoinStyle)
Qt::MiterJoin:斜接(默认,拐角为尖角)Qt::BevelJoin:斜切(拐角为平角)Qt::RoundJoin:圆角(拐角为圆形)
cpp
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 创建自定义画笔
QPen pen;
pen.setColor(Qt::darkGreen); // 设置颜色
pen.setWidth(4); // 设置宽度
pen.setStyle(Qt::DashDotLine); // 设置线条风格
pen.setCapStyle(Qt::RoundCap); // 设置端点样式
pen.setJoinStyle(Qt::RoundJoin);// 设置连接样式
// 应用画笔到绘图器
painter.setPen(pen);
// 用自定义画笔绘制图形
painter.drawRect(50, 50, 200, 150); // 绘制带虚线边框的矩形
painter.drawEllipse(300, 50, 150, 150); // 绘制带虚线边框的椭圆
}

2.2.6 设置画刷
下面是Qt的所有QBrushStyle:

- 构造函数
cpp
// 1. 默认构造:黑色实心填充
QBrush brush;
// 2. 指定颜色和样式构造
QBrush brush(Qt::blue, Qt::Dense4Pattern);
// 3. 用渐变构造
QLinearGradient gradient(0,0,200,0);
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(1, Qt::yellow);
QBrush brush(gradient);
// 4. 用纹理图片构造
QBrush brush(QPixmap("texture.png"));
- 设置方法
cpp
brush.setColor(Qt::green); // 改变填充颜色
brush.setStyle(Qt::CrossPattern); // 改变填充样式
brush.setTexture(QPixmap("new.png"));// 更换纹理图片
cpp
void Widget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// 1. 纯色填充矩形
QBrush solidBrush(Qt::cyan, Qt::SolidPattern);
painter.setBrush(solidBrush);
painter.drawRect(50, 50, 100, 80);
// 2. 交叉线条填充椭圆
QBrush crossBrush(Qt::darkGray, Qt::DiagCrossPattern);
painter.setBrush(crossBrush);
painter.drawEllipse(200, 50, 100, 80);
// 3. 线性渐变填充多边形
QLinearGradient gradient(350, 50, 450, 130);
gradient.setColorAt(0, Qt::red);
gradient.setColorAt(1, Qt::blue);
QBrush gradientBrush(gradient);
painter.setBrush(gradientBrush);
painter.drawPolygon(QPolygon({QPoint(350,50), QPoint(450,50), QPoint(400,130)}));
}

2.3 绘制图片
Qt 图像处理类:QImage(I/O 优化、像素操作)、QPixmap(屏幕显示优化)、QBitmap(黑白图)、QPicture(记录绘图命令),以下以 QPixmap 为例。
| 维度 | QImage | QPixmap | QBitmap | QPicture |
|---|---|---|---|---|
| 核心定位 | 像素操作与I/O | 屏幕显示性能 | 单色图像 | 绘图命令记录 |
| 像素访问 | 支持直接读写 | 不支持 | 不支持 | 无像素数据 |
| 线程安全 | 支持多线程 | 仅UI线程 | 仅UI线程 | 支持多线程 |
| 缩放特性 | 位图缩放会失真 | 位图缩放会失真 | 位图缩放会失真 | 矢量缩放不失真 |
| 典型场景 | 图像编辑、离线处理 | 界面图标、背景 | 黑白遮罩、光标 | 矢量图形保存、绘图重放 |
2.3.1 绘制简单图片
- 添加资源文件(qrc),导入图片。
- 绘制代码:
cpp
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap(0,0,QPixmap(":/picture/4.jpg")); // (x,y,图片路径)
}
2.3.2 平移图片
cpp
painter.translate(100, 100); // 坐标原点平移到(100,100)
painter.drawPixmap(0,0,QPixmap(":/picture/4.jpg"));
2.3.3 缩放图片
cpp
painter.drawPixmap(300, 400, 50,60,QPixmap(":/picture/4.jpg")); // (x,y,目标宽度,目标高度,图片)
2.3.4 旋转图片
cpp
painter.translate(200,300); // 旋转中心(图片中心)
painter.rotate(90); // 顺时针旋转90度
painter.translate(-200,-300); // 原点复原
painter.drawPixmap(0,0,QPixmap(":/picture/4.jpg"));
2.4 其他设置
2.4.1 移动位置
cpp
painter.drawEllipse(QPoint(100,200),50,50);
painter.translate(200,0); // 画家右移200px
painter.drawEllipse(QPoint(100,200),50,50); // 不重合
2.4.2 保存/加载状态
cpp
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); // 与第二个圆重合
2.5 其他绘图类
2.5.1 QPixmap
- 特性:屏幕显示优化,与系统强相关。
- 示例:绘制并保存图片:
cpp
QPixmap pix(500,500);
QPainter painter(&pix);
painter.setPen(Qt::red);
painter.drawEllipse(QPoint(100,100),100,100);
pix.save("C:\\Test_Pic\\pix.png");
2.5.2 QImage
- 特性:像素级操作,跨平台一致。
- 示例:修改图片像素:
cpp
QImage img;
img.load(":/picture/3.jpg");
for(int i=100;i<200;i++){
for(int j=100;j<200;j++){
QRgb rgb = qRgb(0,0,255); // 蓝色
img.setPixel(i,j,rgb);
}
}
painter.drawImage(0,0, img);
2.5.3 QPicture
- 特性:记录 QPainter 操作步骤,跨平台一致,仅支持加载自身存档文件。
- 示例:记录并重现绘图:
cpp
// 记录
QPicture pic;
QPainter painter;
painter.begin(&pic);
painter.setPen(Qt::red);
painter.drawEllipse(QPoint(200,200),100,100);
painter.end();
pic.save("C:\\Test_Pic\\pic.pic");
// 重现
void Widget::paintEvent(QPaintEvent*)
{
QPainter painter(this);
QPicture pic;
pic.load("C:\\Test_Pic\\pic.pic");
painter.drawPicture(0,0,pic);
}