Qt 绘图核心教程:从基础绘制到图像操作全解析

文章目录

    • [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类重绘触发的场景:

  1. 控件首次创建时

    QWidget完成构造并进入显示流程(show()/exec()触发)时,Qt事件循环会向该控件派发QPaintEvent事件,驱动paintEvent(QPaintEvent*)虚函数执行。

  2. 控件被遮挡后解除遮挡

    当QWidget的部分/全部区域被其他顶层窗口/子控件遮挡时,该区域会被Qt标记为「无效区域(Invalid Region)」;遮挡解除后,窗口系统(Windows/X11/macOS)会通知Qt更新无效区域,Qt随即为该区域派发QPaintEvent(仅重绘无效区域,而非全量)。

  3. 窗口被最小化后还原

    窗口最小化时,其对应的系统窗口句柄(HWND/Window ID)会脱离屏幕显示链表,系统会释放该窗口的显存缓冲区(back buffer);窗口还原时,窗口句柄重新关联显示设备,Qt会触发全量QPaintEvent 以重建窗口视觉内容。

  4. 控件大小发生改变时

    QWidget的resize()/setGeometry()等操作导致尺寸/位置变更时,Qt会标记控件整体为无效区域,并派发QPaintEvent

  5. 主动调用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 设置画笔

常用属性与设置方法:

  1. 颜色(Color)

    • 构造时指定:QPen pen(Qt::red);
    • 后期修改:pen.setColor(QColor(0, 128, 255));
  2. 宽度(Width)

    • 整数宽度:pen.setWidth(3);(默认值为1)
    • 浮点宽度:pen.setWidthF(2.5);(支持更精细的宽度控制)
  3. 线条风格(PenStyle)

    • 常用取值pen.setStyle(Qt::DashDotLine);
枚举值 效果
Qt::NoPen 无轮廓(只填充图形内部)
Qt::SolidLine 实线(默认)
Qt::DashLine 虚线(短横线间隔)
Qt::DotLine 点线(点间隔)
Qt::DashDotLine 点划线(横线+点间隔)
Qt::DashDotDotLine 双点划线(横线+两点间隔)
Qt::CustomDashLine 自定义虚线样式
  1. 端点样式(PenCapStyle)

    • Qt::FlatCap:平端(默认,端点与线条边缘齐平)
    • Qt::SquareCap:方端(端点超出线条边缘半个宽度)
    • Qt::RoundCap:圆端(端点为半圆形)
  2. 连接样式(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:

  1. 构造函数
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"));
  1. 设置方法
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 绘制简单图片
  1. 添加资源文件(qrc),导入图片。
  2. 绘制代码:
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);
}
相关推荐
u0109272712 小时前
C++中的模板方法模式
开发语言·c++·算法
山上三树2 小时前
详细介绍读写锁
开发语言·c++·spring
乾元2 小时前
绕过艺术:使用 GANs 对抗 Web 防火墙(WAF)
前端·网络·人工智能·深度学习·安全·架构
HWL56792 小时前
一个CSS属性will-change: transform
前端·css
Y淑滢潇潇2 小时前
WEB 作业 即时内容发布前端交互案例
前端·javascript·交互
比特森林探险记2 小时前
后端开发者快速入门react
开发语言·前端·javascript
苏宸啊2 小时前
string实现
c++
李松桃2 小时前
python第三次作业
java·前端·python
马士兵教育2 小时前
计算机专业学生入行IT行业,编程语言如何选择?
java·开发语言·c++·人工智能·python