🔥个人主页:Cx330🌸
❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》
《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔
《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战
🌟心向往之行必能
🎥Cx330🌸的简介:
目录
前言:
一、 Qt 绘图四大核心角色
1.2 绘图的核心原则
二. 基础绘图:绘制形状与文本
2.1 绘制基础形状
2.1.1 绘制线段
2.1.2 绘制矩形
2.1.3 绘制圆形 / 椭圆
2.1.3 绘制圆形 / 椭圆
2.2 绘制文本
2.3 自定义画笔与画刷
2.3.1 自定义画笔
2.3.2 自定义画刷
三. 图片处理:绘制、缩放与旋转
3.1 绘制图片(QPixmap)
3.2 图片平移与旋转
前言:
在 Qt 开发中,我们经常使用各种各样的控件(如
QPushButton、QLineEdit、QLabel等)。但你是否思考过,这些控件究竟是如何呈现到屏幕上的?答案非常简单:本质上它们都是“画”出来的。Qt 已经提前帮我们绘制好了各种通用控件,拿来即用。但在实际项目中,当预设控件无法满足特殊需求时,我们就需要利用 Qt 提供的绘图 API 手动 DIY 自定义控件与视觉效果。
本文将根据 Qt 绘图的核心知识体系,由浅入深解析 Qt 的绘图机制、核心组件、绘制事件机制以及图像处理类。
一、 Qt 绘图四大核心角色
Qt 的绘图系统采用了一套现实生活中“画画”的拟人化设计概念:
| 类名 | 比喻 | 作用与功能描述 |
| 绘图者(画师) | 提供具体的绘图方法(画线、画矩形、画文字等),负责执行绘画动作。 |
| 画板(绘图设备) | 绘图的目标载体。 |
| 画笔 | 用于绘制图形的轮廓线,控制线条的颜色、粗细、线型(实线、虚线等)。 |
| 画刷 | 用于填充封闭图形的内部区域,控制填充的颜色、渐变色或纹理图案。 |
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 <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* enent); private: Ui::Widget *ui; }; #endif // WIDGET_H// widget.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) { (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 <QPainter> 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); }