深入浅出 Qt 绘图机制:从 QPainter 到四大图像类解析

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》

《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔

《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战

🌟心向往之行必能


🎥Cx330🌸的简介:


目录

前言:

[一、 Qt 绘图四大核心角色](#一、 Qt 绘图四大核心角色)

[1.2 绘图的核心原则](#1.2 绘图的核心原则)

[二. 基础绘图:绘制形状与文本](#二. 基础绘图:绘制形状与文本)

[2.1 绘制基础形状](#2.1 绘制基础形状)

[2.1.1 绘制线段](#2.1.1 绘制线段)

[2.1.2 绘制矩形](#2.1.2 绘制矩形)

[2.1.3 绘制圆形 / 椭圆](#2.1.3 绘制圆形 / 椭圆)

[2.1.3 绘制圆形 / 椭圆](#2.1.3 绘制圆形 / 椭圆)

[2.2 绘制文本](#2.2 绘制文本)

[2.3 自定义画笔与画刷](#2.3 自定义画笔与画刷)

[2.3.1 自定义画笔](#2.3.1 自定义画笔)

[2.3.2 自定义画刷](#2.3.2 自定义画刷)

[三. 图片处理:绘制、缩放与旋转](#三. 图片处理:绘制、缩放与旋转)

[3.1 绘制图片(QPixmap)](#3.1 绘制图片(QPixmap))

[3.2 图片平移与旋转](#3.2 图片平移与旋转)


前言:

在 Qt 开发中,我们经常使用各种各样的控件(如 QPushButton、QLineEdit、QLabel等)。但你是否思考过,这些控件究竟是如何呈现到屏幕上的?

答案非常简单:本质上它们都是"画"出来的。Qt 已经提前帮我们绘制好了各种通用控件,拿来即用。但在实际项目中,当预设控件无法满足特殊需求时,我们就需要利用 Qt 提供的绘图 API 手动 DIY 自定义控件与视觉效果。

本文将根据 Qt 绘图的核心知识体系,由浅入深解析 Qt 的绘图机制、核心组件、绘制事件机制以及图像处理类。


一、 Qt 绘图四大核心角色

Qt 的绘图系统采用了一套现实生活中"画画"的拟人化设计概念:

|------------------|--------------|-----------------------------------------------------------|
| 类名 | 比喻 | 作用与功能描述 |
| QPainter | 绘图者(画师) | 提供具体的绘图方法(画线、画矩形、画文字等),负责执行绘画动作。 |
| QPaintDevice | 画板(绘图设备) | 绘图的目标载体。QWidget是 QPaintDevice的子类,因此所有窗口控件都可以作为画板。 |
| QPen | 画笔 | 用于绘制图形的轮廓线,控制线条的颜色、粗细、线型(实线、虚线等)。 |
| QBrush | 画刷 | 用于填充封闭图形的内部区域,控制填充的颜色、渐变色或纹理图案。 |

1.2 绘图的核心原则

  • 绘图时机 :绘图操作必须在paintEvent事件中执行,该事件会在控件创建、大小改变、被遮挡恢复等场景下自动触发,也可通过**repaint()或update()**主动触发。
  • 设备无关性:QPainter 可在任意 QPaintDevice 子类上绘图,无论是窗口(QWidget)、图片(QPixmap)还是像素缓冲区(QImage),接口完全一致。
  • 状态管理 :QPainter 支持save()(保存当前状态)和restore()(恢复之前状态),方便复杂绘图中的状态切换。

二. 基础绘图:绘制形状与文本

Qt 绘图 API 支持绘制线段、矩形、圆形、文本等基础元素,掌握这些是实现复杂效果的前提。

2.1 绘制基础形状

2.1.1 绘制线段

通过drawLine方法绘制线段,支持两种参数形式:QPoint坐标对或直接传入 x、y 坐标:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this); // 以当前窗口为画板
    // 方式1:使用QPoint指定起点和终点
    painter.drawLine(QPoint(20, 20), QPoint(200, 20));
    // 方式2:直接传入x1,y1,x2,y2
    painter.drawLine(20, 100, 200, 100);
}
2.1.2 绘制矩形

drawRect方法接收矩形左上角坐标和宽高:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 绘制左上角(20,20)、宽100、高50的矩形
    painter.drawRect(20, 20, 100, 50);
}
2.1.3 绘制圆形 / 椭圆

drawEllipse方法通过中心点坐标和 x、y 轴半径绘制,当 x、y 半径相等时即为圆形:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 绘制中心点(100,100)、半径50的圆形
    painter.drawEllipse(QPoint(100, 100), 50, 50);
    // 绘制椭圆(x半径30,y半径50)
    painter.drawEllipse(QPoint(250, 100), 30, 50);
}
2.1.3 绘制圆形 / 椭圆

drawEllipse方法通过中心点坐标和 x、y 轴半径绘制,当 x、y 半径相等时即为圆形:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 绘制中心点(100,100)、半径50的圆形
    painter.drawEllipse(QPoint(100, 100), 50, 50);
    // 绘制椭圆(x半径30,y半径50)
    painter.drawEllipse(QPoint(250, 100), 30, 50);
}

2.2 绘制文本

通过drawText绘制文本,支持设置字体 、颜色等样式:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 设置字体(华文行楷,24号)
    QFont font("华文行楷", 24);
    painter.setFont(font);
    // 设置文本颜色为红色
    painter.setPen(Qt::red);
    // 在矩形区域(100,200,600,150)内绘制文本(自动换行)
    painter.drawText(QRect(100, 200, 600, 150), "天行健,君子以自强不息");
}

2.3 自定义画笔与画刷

默认的画笔和画刷样式单一,通过 QPen 和 QBrush 可实现个性化效果。

2.3.1 自定义画笔

QPen支持设置颜色、宽度、线条样式:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QPen pen(QColor(255, 0, 0)); // 红色画笔
    pen.setWidth(3); // 线宽3像素
    pen.setStyle(Qt::DashLine); // 虚线样式(可选SolidLine、DotLine等)
    painter.setPen(pen); // 画家使用该画笔
    painter.drawEllipse(QPoint(100, 100), 50, 50);
}
2.3.2 自定义画刷

QBrush用于填充封闭图形,支持纯色、渐变、纹理 等填充模式:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 1. 纯色填充(青色)
    QBrush brush(Qt::cyan);
    // 2. 渐变填充(垂直渐变:白色→黑色)
    // QBrush brush(QLinearGradient(0,0,0,200));
    // brush.gradient()->setColorAt(0, Qt::white);
    // brush.gradient()->setColorAt(1, Qt::black);
    // 3. 纹理填充(使用图片)
    // QBrush brush(QPixmap(":/texture.png"));
    
    brush.setStyle(Qt::Dense1Pattern); // 填充样式(可选不同密度的图案)
    painter.setBrush(brush);
    painter.drawEllipse(QPoint(100, 100), 50, 50);
}
  • 补充例子:大家可以看看

    // widget.h
    #ifndef WIDGET_H
    #define WIDGET_H

    #include

    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
    enent);

    private:
    Ui::Widget *ui;
    };
    #endif // WIDGET_H

    // widget.cpp
    #include "widget.h"
    #include "ui_widget.h"

    #include

    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    {
    ui->setupUi(this);
    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::paintEvent(QPaintEvent *event)
    {
    (void)event;
    // 绘图工作就会放在这里执行
    QPainter painter(this);

    复制代码
      // 画一个线段

    // painter.drawLine(20,20,200,20);
    // painter.drawLine(QPoint(20,20),QPoint(200,20));
    // painter.drawLine(20,20,300,200);

    复制代码
      // 画一个矩形

    // painter.drawRect(100,100,300,200);
    // // 画一个圆形
    // painter.drawEllipse(200,200,200,50); // 后面两个参数其实是外接矩形的宽度高度

    复制代码
      // 绘制文本

    // painter.drawText(10,100,"hello");
    // QFont font("微软雅黑", 24);
    // painter.setFont(font);

    复制代码
      QPen pen;
      // 设置成红色的线条
      pen.setColor(QColor(255,0,0));
      // 设置线条的粗细
      pen.setWidth(5);
      // 设置线条的风格
      pen.setStyle(Qt::DashLine);
      // 让 painter 对象应用 pen 对象
      painter.setPen(pen);
    
      QBrush brush;
      brush.setColor(QColor(0,255,0));
      // brush.setStyle(Qt::SolidPattern); 填充风格
      brush.setStyle(Qt::CrossPattern);
      painter.setBrush(brush);
      painter.drawEllipse(200,200,200,50);

    }


三. 图片处理:绘制、缩放与旋转

Qt 提供 QPixmap、QImage、QPicture 三种图片相关绘图设备,分别适用于不同场景。

3.1 绘制图片(QPixmap)

QPixmap 专为屏幕显示优化,加载图片后通过drawPixmap绘制:

复制代码
// 1. 先添加资源文件(res.qrc),导入图片到picture文件夹
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    // 绘制原图(左上角坐标(0,0))
    painter.drawPixmap(0, 0, QPixmap(":/picture/4.jpg"));
    // 缩放绘制(左上角(300,400),宽50,高60)
    painter.drawPixmap(300, 400, 50, 60, QPixmap(":/picture/4.jpg"));
}

3.2 图片平移与旋转

通过translate(坐标平移)和rotate(旋转)实现图片变换,注意旋转默认以原点为中心:

复制代码
void Widget::paintEvent(QPaintEvent *) {
    QPainter painter(this);
    QPixmap pix(":/picture/4.jpg");
    
    // 1. 平移图片(原点偏移(100,100))
    painter.translate(100, 100);
    painter.drawPixmap(0, 0, pix);
    
    // 2. 旋转图片(以图片中心为旋转点)
    painter.save(); // 保存当前状态
    painter.translate(300 + pix.width()/2, 100 + pix.height()/2); // 平移到图片中心
    painter.rotate(90); // 顺时针旋转90度
    painter.translate(-(300 + pix.width()/2), -(100 + pix.height()/2)); // 还原原点
    painter.drawPixmap(300, 100, pix);
    painter.restore(); // 恢复状态
}
  • 补充示例:(.h这里就不再展示了,跟之前的补充示例一样)

    #include "widget.h"
    #include "ui_widget.h"
    #include

    Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    {
    ui->setupUi(this);
    }

    Widget::~Widget()
    {
    delete ui;
    }

    void Widget::paintEvent(QPaintEvent *event)
    {
    (void)event;
    QPainter painter(this);

    复制代码
      QPixmap pixmap(":/ins.png");
    
      // 基础绘制

    // painter.drawPixmap(0,0,pixmap);
    // painter.drawPixmap(100,100,pixmap);

    复制代码
      // 图片缩放

    // painter.drawPixmap(100,100,400,300,pixmap);

    复制代码
      // 图片的旋转, 本质上是把 Qpainter 对象进行了需旋转, 绘制出来的内容也就旋转了
      painter.rotate(180); // 默认绕原点(0,0)旋转,所以会到屏幕外去
      painter.translate(-800,-600); // 我们可以平移一下,但是由于之前旋转了所以坐标轴也变了,现在是用负的
      painter.drawPixmap(100,100,400,300,pixmap);

    }

相关推荐
信可维1 小时前
AI 读 Word 表格总读错?先查合并单元格和表头这 3 处
开发语言·人工智能·c#·word·软件工程
HEJOO92 小时前
Java 并发运行中的安全问题详解
java·开发语言
星夜离尘562 小时前
MATLAB阶跃响应怎么量:别把最后一个采样点当成稳态
开发语言·matlab
云水初2 小时前
【agent篇】RAG Agent避坑指南(附高级RAG Agent汇总)
开发语言·笔记·python·学习·langchain·agent·rag
Littlehero_1212 小时前
QT自定义控件之水泥厂组态(源码开源)
开发语言·qt
江厌012 小时前
128GB 统一内存能跑多大模型?PGX 的容量、带宽与适用边界
性能优化
辛苦才能2 小时前
C++ 哈希表深度解析:删除为什么必须打标记,负载因子为什么卡 0.7
开发语言·数据结构·c++·算法
miller-tsunami3 小时前
STL简介&string相关知识点
开发语言·c++·string
西红柿炖牛腩3543 小时前
机房电脑不能联网,怎么离线把课件里的 3D 模型压小?Draco / Meshopt 参数清单
前端·javascript·3d·性能优化·大屏端