【从零开始的Qt开发指南】(二十三)Qt 界面优化之绘图实战:解锁自定义界面的无限可能


目录

​编辑

前言

[一、Qt 绘图基本概念:理解 "画家、画板、画笔、画刷"](#一、Qt 绘图基本概念:理解 “画家、画板、画笔、画刷”)

[1.1 绘图核心四要素](#1.1 绘图核心四要素)

[1.2 绘图的关键:paintEvent 事件](#1.2 绘图的关键:paintEvent 事件)

[1.3 第一个绘图程序:绘制一条直线](#1.3 第一个绘图程序:绘制一条直线)

[步骤 1:在头文件中声明 paintEvent 事件](#步骤 1:在头文件中声明 paintEvent 事件)

[步骤 2:在源文件中实现绘图逻辑](#步骤 2:在源文件中实现绘图逻辑)

[步骤 3:运行效果](#步骤 3:运行效果)

二、绘制各种形状:从基础图形到自定义图案

[2.1 绘制直线(drawLine)](#2.1 绘制直线(drawLine))

[方法 1:通过 QPoint 指定起点和终点](#方法 1:通过 QPoint 指定起点和终点)

[方法 2:通过坐标值直接指定](#方法 2:通过坐标值直接指定)

完整示例

[2.2 绘制矩形(drawRect)](#2.2 绘制矩形(drawRect))

示例:绘制一个简单矩形

[2.3 绘制圆形 / 椭圆(drawEllipse)](#2.3 绘制圆形 / 椭圆(drawEllipse))

示例:绘制圆形

[2.4 绘制文本(drawText)](#2.4 绘制文本(drawText))

示例:绘制带样式的文本

[2.5 自定义画笔(QPen):控制线条样式](#2.5 自定义画笔(QPen):控制线条样式)

[QPen 的核心方法](#QPen 的核心方法)

常用线型(Qt::PenStyle)

示例:自定义画笔绘制圆形

[2.6 自定义画刷(QBrush):填充封闭区域](#2.6 自定义画刷(QBrush):填充封闭区域)

常用填充样式(Qt::BrushStyle)

示例:使用画刷填充圆形

三、绘制图片:加载、平移、缩放与旋转

[3.1 绘制简单图片(drawPixmap)](#3.1 绘制简单图片(drawPixmap))

实现步骤

[步骤 1:准备图片资源](#步骤 1:准备图片资源)

[步骤 2:绘制图片代码](#步骤 2:绘制图片代码)

运行效果:图片从窗口左上角开始显示,尺寸与原图一致。

[3.2 平移图片(translate)](#3.2 平移图片(translate))

示例:平移图片

[3.3 缩放图片](#3.3 缩放图片)

示例:同时显示原图和缩放图

[3.4 旋转图片(rotate)](#3.4 旋转图片(rotate))

方法原型

[示例:以图片中心为旋转中心旋转 90 度](#示例:以图片中心为旋转中心旋转 90 度)

关键步骤解析

四、绘图高级设置:移动画家、保存与恢复状态

[4.1 移动画家位置(translate)](#4.1 移动画家位置(translate))

示例:绘制两个不重合的圆形

[4.2 保存与恢复画家状态(save/restore)](#4.2 保存与恢复画家状态(save/restore))

示例:保存状态后绘制多个图形

运行效果

应用场景

五、特殊的绘图设备:QPixmap、QImage、QPicture

[5.1 QPixmap:屏幕显示优化](#5.1 QPixmap:屏幕显示优化)

[示例:使用 QPixmap 绘制图形并保存](#示例:使用 QPixmap 绘制图形并保存)

运行效果

[5.2 QImage:像素级操作](#5.2 QImage:像素级操作)

[示例 1:使用 QImage 绘制图形并保存](#示例 1:使用 QImage 绘制图形并保存)

[示例 2:修改图片像素](#示例 2:修改图片像素)

运行效果

[5.3 QPicture:记录绘图指令](#5.3 QPicture:记录绘图指令)

示例:记录绘图指令并重演

运行效果

应用场景

总结


前言

在 Qt 开发中,自带的标准控件虽然能满足大部分基础需求,但面对个性化、高定制化的界面设计时,往往显得力不从心。想象一下,你需要实现一个炫酷的自定义仪表盘、动态变化的波形图,或是带有独特纹理的异形按钮 ------ 这时,Qt 的绘图 API 就成了你的 "秘密武器"。

Qt 提供了一套强大且灵活的绘图框架,让开发者能够直接在窗口或控件上绘制任意图形、文字、图片,甚至实现复杂的动画效果。本文将从绘图的基本概念、各种形状绘制、图片操作、高级设置到特殊绘图设备,进行全方位、手把手的实战教学,带你从零掌握 Qt 绘图技巧,让你的界面突破标准控件的限制!下面就让我们正式开始吧!


一、Qt 绘图基本概念:理解 "画家、画板、画笔、画刷"

在开始绘图之前,我们需要先理解 Qt 绘图框架的核心组成 ------ 四个关键类,它们的关系就像现实中的绘画场景,非常容易理解:

1.1 绘图核心四要素

类名 类比角色 核心作用
QPainter 画家 负责执行绘图操作,提供drawLinedrawRectdrawEllipse等一系列绘图方法
QPaintDevice 画板 绘图的载体,即 "画在哪里",如 QWidget、QPixmap、QImage 等
QPen 画笔 控制线条的样式,包括颜色、宽度、线型(实线、虚线等)
QBrush 画刷 控制封闭区域的填充效果,包括纯色、渐变、纹理等

简单来说:QPainter(画家)拿着 QPen(画笔)和 QBrush(画刷),在 QPaintDevice(画板)上创作。这四个类协同工作,构成了 Qt 绘图的基础。

1.2 绘图的关键:paintEvent 事件

与直接在构造函数中绘图不同,Qt 绘图必须在**paintEvent事件中执行。这是因为paintEvent**会在特定场景下自动触发,确保绘图效果始终保持正确:

  • 控件首次创建时
  • 控件被遮挡后重新显示时
  • 窗口最小化后恢复时
  • 控件大小发生变化时
  • 主动调用**repaint()update()**方法时

如果在构造函数中绘图,一旦上述场景发生,绘制的内容会被自动清除,无法保持。因此,所有绘图代码都必须放在**paintEvent**的重写函数中。

1.3 第一个绘图程序:绘制一条直线

下面通过一个最简单的示例,演示 Qt 绘图的基本流程:

步骤 1:在头文件中声明 paintEvent 事件

cpp 复制代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    // 声明绘图事件(必须重写此事件进行绘图)
    void paintEvent(QPaintEvent *event) override;
};

#endif // WIDGET_H

步骤 2:在源文件中实现绘图逻辑

cpp 复制代码
// widget.cpp
#include "widget.h"
#include <QPainter> // 包含绘图核心类头文件

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
}

Widget::~Widget()
{
}

void Widget::paintEvent(QPaintEvent *)
{
    // 1. 创建画家对象,指定画板为当前窗口(this指针)
    QPainter painter(this);

    // 2. 绘制一条直线:从坐标(20,20)到(200,20)
    painter.drawLine(QPoint(20, 20), QPoint(200, 20));
}
步骤 3:运行效果

编译并运行程序,会在窗口顶部看到一条水平直线。这就是 Qt 绘图的最基本流程:创建画家、指定画板、调用绘图方法。

二、绘制各种形状:从基础图形到自定义图案

Qt 的 QPainter 类提供了丰富的绘图方法,支持绘制直线、矩形、圆形、椭圆、文本等多种基础形状。下面我们逐一介绍这些形状的绘制方法,并结合画笔和画刷进行样式定制。

2.1 绘制直线(drawLine)

QPainter 提供了两种重载的**drawLine**方法,分别适用于不同场景:

方法 1:通过 QPoint 指定起点和终点

cpp 复制代码
// 原型:void drawLine(const QPoint &p1, const QPoint &p2)
painter.drawLine(QPoint(20, 20), QPoint(200, 20)); // 水平直线
painter.drawLine(QPoint(20, 50), QPoint(200, 50)); // 另一条水平直线

方法 2:通过坐标值直接指定

cpp 复制代码
// 原型:void drawLine(int x1, int y1, int x2, int y2)
painter.drawLine(20, 80, 200, 80); // 无需创建QPoint对象,更简洁

完整示例

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 绘制三条不同位置的水平直线
    painter.drawLine(QPoint(20, 20), QPoint(200, 20));
    painter.drawLine(20, 50, 200, 50);
    painter.drawLine(QPoint(20, 80), QPoint(200, 80));
}

运行效果:窗口中显示三条平行的水平直线,间距为 30px。

2.2 绘制矩形(drawRect)

绘制矩形需要指定左上角坐标和矩形的宽高,**drawRect**方法的原型如下:

cpp 复制代码
void drawRect(int x, int y, int width, int height);
  • x, y:矩形左上角在窗口中的坐标
  • width, height:矩形的宽度和高度

示例:绘制一个简单矩形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 绘制矩形:左上角(20,20),宽100px,高50px
    painter.drawRect(20, 20, 100, 50);
}

运行效果:窗口左上角显示一个黑色边框的矩形(默认画笔样式)。

2.3 绘制圆形 / 椭圆(drawEllipse)

drawEllipse方法可以绘制椭圆,当椭圆的长半轴和短半轴相等时,就变成了圆形。其常用原型如下:

cpp 复制代码
void drawEllipse(const QPoint &center, int rx, int ry);
  • center:椭圆的中心点坐标
  • rx:水平方向半径(长半轴)
  • ry:垂直方向半径(短半轴)

示例:绘制圆形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 绘制圆形:中心点(100,100),水平半径50px,垂直半径50px
    painter.drawEllipse(QPoint(100, 100), 50, 50);
}

运行效果:显示一个正圆形。

2.4 绘制文本(drawText)

QPainter 不仅能绘制图形,还能绘制文本,并支持自定义字体、颜色等样式。常用方法如下:

cpp 复制代码
// 设置字体
void setFont(const QFont &font);
// 绘制文本:在指定矩形区域内显示文本
void drawText(const QRect &rect, const QString &text);

示例:绘制带样式的文本

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 设置字体:华文行楷,24号字
    QFont font("华文行楷", 24);
    painter.setFont(font);

    // 2. 设置画笔颜色(文本颜色由画笔决定)
    painter.setPen(Qt::red);

    // 3. 绘制文本:在矩形(100,200,600,150)内显示"天行健,君子以自强不息"
    painter.drawText(QRect(100, 200, 600, 150), "天行健,君子以自强不息");
}

运行效果:窗口中显示红色、24 号华文行楷字体的文本,文本位于指定矩形区域内。

2.5 自定义画笔(QPen):控制线条样式

默认情况下,QPainter 使用黑色、1px 宽的实线画笔。通过 QPen 类,我们可以自定义画笔的颜色、宽度、线型等属性,让线条更具个性化。

QPen 的核心方法

方法 作用 示例值
QPen(const QColor &color) 构造函数:指定画笔颜色 QColor (255, 0, 0)(红色)
setWidth(int width) 设置画笔宽度 3(3px 宽)
setStyle(Qt::PenStyle) 设置线型 Qt::DashLine(虚线)

常用线型(Qt::PenStyle)

线型常量 说明
Qt::SolidLine 实线(默认)
Qt::DashLine 虚线(由短横线组成)
Qt::DotLine 点线(由点组成)
Qt::DashDotLine 点划线(交替的横线和点)
Qt::DashDotDotLine 双点划线(横线 + 两个点的循环)
Qt::NoPen 无线条(只填充内部,不绘制边框)

示例:自定义画笔绘制圆形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 创建画笔:红色
    QPen pen(QColor(255, 0, 0));

    // 2. 设置画笔宽度:3px
    pen.setWidth(3);

    // 3. 设置线型:虚线
    pen.setStyle(Qt::DashLine);

    // 4. 让画家使用该画笔
    painter.setPen(pen);

    // 5. 绘制圆形
    painter.drawEllipse(QPoint(100, 100), 50, 50);
}

运行效果:显示一个红色、3px 宽、虚线边框的圆形。

2.6 自定义画刷(QBrush):填充封闭区域

QBrush 用于填充封闭图形的内部区域,支持纯色、渐变、纹理等多种填充模式。其核心方法如下:

cpp 复制代码
// 构造函数:指定填充颜色
QBrush(const QColor &color);
// 设置填充样式
void setStyle(Qt::BrushStyle style);

常用填充样式(Qt::BrushStyle)

样式常量 说明
Qt::SolidPattern 纯色填充(默认)
Qt::Dense1Pattern ~ Qt::Dense7Pattern 不同密度的点填充
Qt::HorPattern 水平线条填充
Qt::VerPattern 垂直线条填充
Qt::CrossPattern 十字线填充
Qt::LinearGradientPattern 线性渐变填充
Qt::RadialGradientPattern 径向渐变填充
Qt::TexturePattern 纹理图片填充

示例:使用画刷填充圆形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 设置画笔(边框样式)
    QPen pen(QColor(255, 0, 0));
    pen.setWidth(3);
    pen.setStyle(Qt::DashLine);
    painter.setPen(pen);

    // 2. 设置画刷(填充样式):青色,高密度点填充
    QBrush brush(Qt::cyan);
    brush.setStyle(Qt::Dense1Pattern);
    painter.setBrush(brush);

    // 3. 绘制圆形(会自动填充内部)
    painter.drawEllipse(QPoint(100, 100), 50, 50);
}

运行效果:圆形边框为红色虚线,内部填充青色高密度点图案。

三、绘制图片:加载、平移、缩放与旋转

Qt 提供了 QPixmap、QImage 等类处理图片,其中 QPixmap 专门用于屏幕显示优化,是绘图中加载和显示图片的首选。下面我们介绍图片的基本绘制、平移、缩放、旋转等常用操作。

3.1 绘制简单图片(drawPixmap)

绘制图片的核心方法是drawPixmap,其原型如下:

cpp 复制代码
void drawPixmap(int x, int y, const QPixmap &pixmap);
  • x, y:图片在窗口中的左上角坐标
  • pixmap:要绘制的图片对象(通过文件路径加载)

实现步骤

步骤 1:准备图片资源
  1. 在项目文件夹中创建picture文件夹,放入图片文件(如 4.jpg)。
  2. 在 Qt Creator 中右键项目 -> 新建文件 -> Qt -> Qt Resource File,创建res.qrc资源文件。
  3. 打开res.qrc,点击 "Add Prefix"(默认前缀为 "/"),再点击 "Add Files",选择picture文件夹中的图片。
步骤 2:绘制图片代码

头文件:

cpp 复制代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    void paintEvent(QPaintEvent *event) override;
};

#endif // WIDGET_H

源文件:

cpp 复制代码
// widget.cpp
#include "widget.h"
#include <QPainter>
#include <QPixmap>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
}

Widget::~Widget()
{
}

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

    // 加载图片(资源文件路径::/picture/4.jpg)
    QPixmap pixmap(":/picture/4.jpg");

    // 绘制图片:左上角坐标(0,0)
    painter.drawPixmap(0, 0, pixmap);
}

运行效果:图片从窗口左上角开始显示,尺寸与原图一致。

3.2 平移图片(translate)

图片平移本质上是改变绘图坐标的原点,通过 QPainter 的translate方法实现:

cpp 复制代码
// 平移坐标原点:将原点移动到(x, y)
void translate(int x, int y);

示例:平移图片

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 平移坐标原点:向右平移100px,向下平移100px
    painter.translate(100, 100);

    // 2. 绘制图片:此时(0,0)对应原坐标的(100,100)
    painter.drawPixmap(0, 0, QPixmap(":/picture/4.jpg"));
}

运行效果:图片从原坐标 (100,100) 位置开始显示,相当于向右下方平移了 100px。

3.3 缩放图片

缩放图片可以通过drawPixmap的重载方法实现,直接指定绘制后的图片尺寸。

cpp 复制代码
void drawPixmap(int x, int y, int width, int height, const QPixmap &pixmap);
  • width, height:缩放后的图片宽度和高度

示例:同时显示原图和缩放图

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    QPixmap pixmap(":/picture/4.jpg");

    // 1. 绘制原图:左上角(0,0),尺寸与原图一致
    painter.drawPixmap(0, 0, pixmap);

    // 2. 绘制缩放图:左上角(300,400),尺寸缩放到50x60px
    painter.drawPixmap(300, 400, 50, 60, pixmap);
}

运行效果:窗口左上角显示原图,右下角显示缩小后的图片。

3.4 旋转图片(rotate)

图片旋转通过rotate方法实现,默认以坐标原点为旋转中心。如果需要以图片中心为旋转中心,需要结合translate方法调整坐标。

方法原型

cpp 复制代码
// 顺时针旋转angle度(角度制)
void rotate(qreal angle);

示例:以图片中心为旋转中心旋转 90 度

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    QPixmap pixmap(":/picture/4.jpg");

    // 1. 获取图片尺寸
    int pixWidth = pixmap.width();
    int pixHeight = pixmap.height();

    // 2. 平移坐标原点到图片中心(目标旋转中心)
    painter.translate(200, 300);

    // 3. 顺时针旋转90度
    painter.rotate(90);

    // 4. 还原坐标原点(确保图片左上角对齐旋转中心)
    painter.translate(-200, -300);

    // 5. 绘制图片
    painter.drawPixmap(200 - pixHeight/2, 300 - pixWidth/2, pixmap);
}

关键步骤解析

  1. 先将坐标原点平移到目标旋转中心(如 (200,300))。
  2. 执行旋转操作(旋转 90 度)。
  3. 将坐标原点还原,避免后续操作受影响。
  4. 绘制图片时,调整图片位置,确保旋转中心与图片中心重合。

运行效果:图片以 (200,300) 为中心顺时针旋转 90 度。

四、绘图高级设置:移动画家、保存与恢复状态

在复杂绘图场景中,我们经常需要绘制多个图形,或对画家状态进行临时调整。Qt 提供了移动画家位置、保存 / 恢复画家状态等功能,让绘图更灵活。

4.1 移动画家位置(translate)

除了用于图片平移,translate方法还可以用于移动画家位置,避免多个图形重合。

示例:绘制两个不重合的圆形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 绘制第一个圆:中心点(100,200)
    painter.drawEllipse(QPoint(100, 200), 50, 50);

    // 2. 移动画家位置:向右平移200px
    painter.translate(200, 0);

    // 3. 绘制第二个圆:此时(100,200)对应原坐标(300,200)
    painter.drawEllipse(QPoint(100, 200), 50, 50);
}

运行效果:窗口中显示两个并排的圆形,间距为 200px,不会重合。

4.2 保存与恢复画家状态(save/restore)

当我们临时修改了画家的画笔、画刷、坐标等状态后,可能需要恢复到之前的状态。QPainter 提供了saverestore方法,通过栈结构管理状态:

  • save():保存当前画家状态(压入栈)。
  • restore():恢复到最近一次保存的状态(弹出栈)。

示例:保存状态后绘制多个图形

cpp 复制代码
void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    // 1. 绘制第一个圆(默认状态)
    painter.drawEllipse(QPoint(100, 200), 50, 50);

    // 2. 移动画家位置并保存状态
    painter.translate(200, 0);
    painter.save(); // 保存"平移200px"后的状态

    // 3. 绘制第二个圆(平移后的位置)
    painter.drawEllipse(QPoint(100, 200), 50, 50);

    // 4. 再次移动画家位置
    painter.translate(200, 0);

    // 5. 恢复到最近保存的状态(平移200px的状态)
    painter.restore();

    // 6. 绘制第三个圆(恢复后的位置,与第二个圆重合)
    painter.drawEllipse(QPoint(100, 200), 50, 50);
}

运行效果

  • 第一个圆在原坐标 (100,200)。
  • 第二个圆在原坐标 (300,200)(平移 200px)。
  • 第三个圆恢复到平移 200px 的状态,与第二个圆重合,最终显示两个圆。

应用场景

  • 临时修改画笔 / 画刷样式后,需要恢复默认样式。
  • 多次平移、旋转后,需要回到之前的坐标状态。

五、特殊的绘图设备:QPixmap、QImage、QPicture

除了 QWidget,Qt 还提供了三种特殊的绘图设备,分别适用于不同场景:

  • QPixmap:优化屏幕显示,适合绘制到控件上。
  • QImage:支持像素级操作,适合图片处理。
  • QPicture:记录绘图指令,适合存档和重演。

5.1 QPixmap:屏幕显示优化

QPixmap 是专门为屏幕显示设计的绘图设备,与系统显示硬件紧密相关,显示效率高。其核心特性:

  • 支持直接加载图片文件。
  • 可作为 QPainter 的画板,绘制图形后保存为图片文件。
  • 不同系统下显示效果可能略有差异(与系统渲染机制相关)。

示例:使用 QPixmap 绘制图形并保存

cpp 复制代码
// widget.cpp
#include "widget.h"
#include <QPainter>
#include <QPixmap>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 1. 创建QPixmap绘图设备:尺寸500x500
    QPixmap pix(500, 500);

    // 2. 创建画家,指定画板为pix
    QPainter painter(&pix);

    // 3. 设置画笔颜色为红色
    painter.setPen(Qt::red);

    // 4. 绘制圆形:中心点(100,100),半径100px
    painter.drawEllipse(QPoint(100, 100), 100, 100);

    // 5. 保存绘制结果到文件(C盘Test_Pic文件夹)
    pix.save("C:\\Users\\Lenovo\\Desktop\\Test_Pic\\pix.png");
}

void Widget::paintEvent(QPaintEvent *)
{
    // 此处无需额外绘图,上述操作在构造函数中执行
}

运行效果

程序运行后,会在C:\Users\Lenovo\Desktop\Test_Pic文件夹中生成pix.png文件,图片中包含一个红色边框的圆形。

5.2 QImage:像素级操作

QImage 是独立于硬件的绘图设备,支持直接访问和修改像素,适合图片处理场景。其核心特性:

  • 支持像素级操作(setPixel方法)。
  • 不同系统下显示效果一致(跨平台兼容性好)。
  • 适合 I/O 操作(加载、保存图片)。

示例 1:使用 QImage 绘制图形并保存

cpp 复制代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 1. 创建QImage绘图设备:尺寸500x500,格式RGB32(32位彩色)
    QImage img(500, 500, QImage::Format_RGB32);

    // 2. 填充背景色为白色(默认背景为黑色)
    img.fill(Qt::white);

    // 3. 创建画家,指定画板为img
    QPainter painter(&img);

    // 4. 设置画笔颜色为青色
    painter.setPen(QPen(Qt::cyan));

    // 5. 绘制圆形:中心点(200,200),半径100px
    painter.drawEllipse(QPoint(200, 200), 100, 100);

    // 6. 保存图片
    img.save("C:\\Users\\Lenovo\\Desktop\\Test_Pic\\img.jpg");
}

运行结果:

示例 2:修改图片像素

头文件:

cpp 复制代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    void paintEvent(QPaintEvent *event) override;
};

#endif // WIDGET_H

源文件:

cpp 复制代码
// widget.cpp
#include "widget.h"
#include <QPainter>
#include <QImage>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
}

Widget::~Widget()
{
}

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

    // 1. 加载图片
    QImage img;
    img.load(":/picture/3.jpg");

    // 2. 修改像素:将坐标(100~200, 100~200)的区域改为蓝色
    for (int i = 100; i < 200; i++) {
        for (int j = 100; j < 200; j++) {
            // qRgb(0,0,255)表示蓝色
            QRgb rgb = qRgb(0, 0, 255);
            img.setPixel(i, j, rgb);
        }
    }

    // 3. 绘制修改后的图片
    painter.drawImage(0, 0, img);
}

运行效果

示例 1 生成一张白色背景、青色圆形的图片;

示例 2 加载原图后,将中间 100x100px 的区域改为蓝色并显示。

5.3 QPicture:记录绘图指令

QPicture 是一种特殊的绘图设备,它不存储图片像素,而是记录 QPainter 的绘图指令(如drawLinedrawRect等),后续可以通过这些指令重演绘图过程。其核心特性:

  • 记录绘图指令,文件体积小。
  • 跨平台兼容性好,重演效果一致。
  • 只能加载 QPicture 格式的文件(.pic),不能加载 png、jpg 等普通图片。

示例:记录绘图指令并重演

头文件:

cpp 复制代码
// widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

protected:
    void paintEvent(QPaintEvent *event) override;
};

#endif // WIDGET_H

源文件:

cpp 复制代码
// widget.cpp
#include "widget.h"
#include <QPainter>
#include <QPicture>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 1. 创建QPicture对象
    QPicture pic;

    // 2. 创建画家,开始记录绘图指令
    QPainter painter;
    painter.begin(&pic);

    // 3. 绘制图形(指令会被记录到pic中)
    painter.setPen(QPen(Qt::red));
    painter.drawEllipse(QPoint(200, 200), 100, 100);

    // 4. 结束记录
    painter.end();

    // 5. 保存记录的指令到文件
    pic.save("C:\\Users\\Lenovo\\Desktop\\Test_Pic\\pic.pic");
}

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

    // 1. 创建QPicture对象,加载保存的指令文件
    QPicture pic;
    pic.load("C:\\Users\\Lenovo\\Desktop\\Test_Pic\\pic.pic");

    // 2. 重演绘图指令
    painter.drawPicture(0, 0, pic);
}

运行效果

程序运行时,会先记录绘制红色圆形的指令并保存为pic.pic文件,然后在paintEvent中重演该指令,在窗口中显示红色圆形。

应用场景

  • 复杂绘图的存档与回放(如数据可视化图表的历史记录)。
  • 跨平台的绘图指令传输(无需担心像素格式差异)。

总结

通过本文的学习,相信你已经掌握了 Qt 绘图的核心技巧和实战方法。绘图是 Qt 界面优化的重要手段,能够帮助你实现各种个性化、高定制化的界面需求。建议在实际项目中多动手实践,结合具体场景灵活运用画笔、画刷、坐标变换等功能,不断提升绘图能力。祝你在 Qt 开发之路上,打造出更多炫酷、实用的自定义界面!

至此有关于Qt开发的基础知识已经全部为大家介绍完毕!后续我还会带大家利用Qt从零开始搭建一个企业级项目,敬请期待!

相关推荐
用户805533698034 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner4 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz9 天前
QML Hello World 入门示例
qt
xcyxiner12 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner13 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner13 天前
DicomViewer (添加模型类)3
qt
xcyxiner14 天前
DicomViewer (目录调整) 2
qt
xcyxiner14 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00616 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术16 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript