当前位置: 首页 > backend >正文

Qt绘图功能学习笔记

Qt绘图功能学习笔记

1. 绘图基础概述

在Qt中,绘图功能主要通过QPainter类实现。QPainter提供了高度优化的函数,用于在各种设备(如QWidget、QPixmap、QImage等)上进行绘制操作。Qt的绘图系统基于画家模型(Painter Model),这意味着绘图操作会按照代码的顺序进行叠加,后绘制的内容会覆盖先绘制的内容。

1.1 绘图的基本流程

  1. 创建QPainter对象
  2. 设置绘图属性(如画笔、画刷、字体等)
  3. 执行绘图操作
  4. 结束绘图

1.2 绘图的时机

在Qt中,绘图通常在以下情况下进行:

  1. 重写QWidget的paintEvent()方法
  2. 在QPixmap或QImage上绘图
  3. 打印文档时

2. QPainter类详解

2.1 创建QPainter对象

// 在窗口部件上绘图
QPainter painter(this);  // this指向QWidget子类实例// 在QPixmap上绘图
QPixmap pixmap(400, 300);
QPainter painter(&pixmap);// 在QImage上绘图
QImage image(400, 300, QImage::Format_RGB32);
QPainter painter(&image);

2.2 设置绘图属性

2.2.1 设置画笔(QPen)

画笔用于绘制线条和形状的轮廓。

// 创建并设置画笔
QPen pen;                        // 创建默认画笔
pen.setWidth(5);                 // 设置线宽为5像素
pen.setColor(QColor(200, 100, 50)); // 设置颜色为RGB值
// 或者使用命名颜色
// pen.setColor(QColor("#888888")); // 使用十六进制颜色值
// pen.setColor(Qt::red);           // 使用Qt预定义颜色// 设置线条样式
// pen.setStyle(Qt::DashLine);      // 虚线
// pen.setStyle(Qt::DotLine);       // 点线
// pen.setStyle(Qt::DashDotLine);   // 点划线
// pen.setStyle(Qt::DashDotDotLine); // 点点划线// 设置端点样式
// pen.setCapStyle(Qt::RoundCap);   // 圆形端点
// pen.setCapStyle(Qt::SquareCap);  // 方形端点
// pen.setCapStyle(Qt::FlatCap);    // 平直端点// 设置连接样式
// pen.setJoinStyle(Qt::RoundJoin); // 圆形连接
// pen.setJoinStyle(Qt::BevelJoin); // 斜角连接
// pen.setJoinStyle(Qt::MiterJoin); // 尖角连接// 将画笔应用到画家
painter.setPen(pen);// 也可以直接使用简化方式
// painter.setPen(QPen(QColor(200, 100, 50), 5, Qt::SolidLine));
2.2.2 设置画刷(QBrush)

画刷用于填充形状的内部。

// 创建并设置画刷
QBrush brush(QColor(200, 100, 50));  // 创建纯色画刷// 设置画刷样式
// brush.setStyle(Qt::SolidPattern);     // 纯色填充
// brush.setStyle(Qt::Dense1Pattern);    // 密集点模式1
// brush.setStyle(Qt::HorPattern);       // 水平线模式
// brush.setStyle(Qt::VerPattern);       // 垂直线模式
// brush.setStyle(Qt::CrossPattern);     // 十字线模式
// brush.setStyle(Qt::DiagCrossPattern); // 对角线模式// 使用渐变填充
// QLinearGradient gradient(0, 0, 100, 100);
// gradient.setColorAt(0, Qt::white);
// gradient.setColorAt(1, Qt::black);
// QBrush brush(gradient);// 使用纹理填充
// QPixmap pixmap("pattern.png");
// QBrush brush(pixmap);// 将画刷应用到画家
painter.setBrush(brush);
2.2.3 设置字体
QFont font("Arial", 12, QFont::Bold);
// font.setItalic(true);  // 设置为斜体
// font.setUnderline(true);  // 设置下划线
// font.setStrikeOut(true);  // 设置删除线
// font.setLetterSpacing(QFont::AbsoluteSpacing, 2);  // 设置字符间距painter.setFont(font);
2.2.4 设置渲染提示
// 设置抗锯齿
painter.setRenderHint(QPainter::Antialiasing);// 设置文本抗锯齿
// painter.setRenderHint(QPainter::TextAntialiasing);// 设置平滑图片变换
// painter.setRenderHint(QPainter::SmoothPixmapTransform);// 设置高质量抗锯齿
// painter.setRenderHint(QPainter::HighQualityAntialiasing);

2.3 坐标系统和变换

2.3.1 基本坐标系统

Qt的坐标系统原点在左上角,X轴向右,Y轴向下。

2.3.2 坐标变换
// 平移坐标系
painter.translate(100, 50);  // 将原点移动到(100, 50)// 旋转坐标系
painter.rotate(45);  // 顺时针旋转45度// 缩放坐标系
painter.scale(2.0, 1.5);  // X轴放大2倍,Y轴放大1.5倍// 复位变换
painter.resetTransform();// 保存和恢复状态
painter.save();  // 保存当前状态
// 进行一些变换和绘图操作
painter.restore();  // 恢复之前的状态

3. 绘图操作详解

3.1 绘制基本图形

3.1.1 绘制点
painter.drawPoint(10, 10);  // 在(10, 10)位置绘制一个点// 绘制多个点
QVector<QPoint> points;
points << QPoint(10, 10) << QPoint(20, 30) << QPoint(40, 50);
painter.drawPoints(points);
3.1.2 绘制线条
// 绘制一条线
painter.drawLine(400, 400, 500, 500);  // 从(400, 400)到(500, 500)的线// 也可以使用QLine或QLineF
// painter.drawLine(QLine(400, 400, 500, 500));
// painter.drawLine(QLineF(400.0, 400.0, 500.0, 500.0));  // 浮点精度// 绘制多条线
QVector<QLine> lines;
lines << QLine(10, 10, 50, 50) << QLine(60, 10, 100, 50);
painter.drawLines(lines);
3.1.3 绘制矩形
// 绘制矩形
painter.drawRect(200, 100, 100, 100);  // 左上角(200, 100),宽100,高100// 也可以使用QRect或QRectF
// painter.drawRect(QRect(200, 100, 100, 100));
// painter.drawRect(QRectF(200.0, 100.0, 100.0, 100.0));  // 浮点精度// 绘制圆角矩形
// painter.drawRoundedRect(200, 100, 100, 100, 10, 10);  // 圆角半径为10
3.1.4 绘制椭圆和圆
// 绘制椭圆
painter.drawEllipse(200, 200, 50, 100);  // 中心(200, 200),宽50,高100// 绘制圆
// painter.drawEllipse(200, 200, 50, 50);  // 中心(200, 200),半径50
3.1.5 绘制多边形
// 绘制三角形
QPolygon polygon;
polygon.setPoints(3, 100, 20, 200, 50, 300, 300);
painter.drawPolygon(polygon);// 也可以使用QVector<QPoint>构建多边形
// QVector<QPoint> points;
// points << QPoint(100, 20) << QPoint(200, 50) << QPoint(300, 300);
// painter.drawPolygon(QPolygon(points));
3.1.6 绘制弧、弦和扇形
// 绘制弧
painter.drawArc(100, 100, 100, 100, 30 * 16, 120 * 16);  // 角度以1/16度为单位// 绘制弦(弧加上连接两端的直线)
// painter.drawChord(100, 100, 100, 100, 30 * 16, 120 * 16);// 绘制扇形(弧加上连接到中心的两条线)
// painter.drawPie(100, 100, 100, 100, 30 * 16, 120 * 16);

3.2 绘制文本

// 绘制文本
QRectF rectF(0, 0, 200, 100);
painter.drawText(rectF, Qt::AlignHCenter, "正点原子");// 设置文本对齐方式
// painter.drawText(rectF, Qt::AlignLeft | Qt::AlignTop, "左上对齐");
// painter.drawText(rectF, Qt::AlignRight | Qt::AlignBottom, "右下对齐");
// painter.drawText(rectF, Qt::AlignCenter, "居中对齐");// 绘制带边框的文本
// painter.drawText(rectF, Qt::AlignCenter | Qt::TextWordWrap, "这是一段长文本,会自动换行", &boundingRect);
// painter.drawRect(boundingRect);  // 绘制文本边框

3.3 绘制图像

// 加载图像
QImage image("example.png");// 绘制图像
painter.drawImage(10, 10, image);  // 在(10, 10)位置绘制图像// 缩放绘制
// painter.drawImage(QRect(10, 10, 200, 150), image);  // 缩放到指定大小// 绘制图像的一部分
// painter.drawImage(QPoint(10, 10), image, QRect(0, 0, 100, 100));  // 只绘制图像左上角100x100的部分

3.4 绘制路径

// 创建路径
QPainterPath path;
path.moveTo(20, 80);       // 移动到起点
path.lineTo(20, 30);       // 添加直线
path.cubicTo(80, 0, 50, 50, 80, 80);  // 添加三次贝塞尔曲线// 添加其他形状到路径
// path.addRect(100, 100, 50, 50);  // 添加矩形
// path.addEllipse(200, 200, 50, 50);  // 添加椭圆
// path.addText(300, 300, QFont("Arial", 12), "文本");  // 添加文本// 绘制路径
painter.drawPath(path);

4. 实例分析

以下是一个完整的绘图示例,展示了如何在QWidget中重写paintEvent方法来实现各种绘图操作。

4.1 头文件 (widget.h)

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();void paintEvent(QPaintEvent *event) override;private:Ui::Widget *ui;
};
#endif // WIDGET_H

4.2 实现文件 (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)
{Q_UNUSED(event)  // 未使用的参数,避免编译警告// 创建QPainter对象,this是指定给图的对象QPainter painter(this);// 设置抗锯齿,使绘制的图形边缘平滑painter.setRenderHint(QPainter::Antialiasing);// 创建并设置画笔QPen pen;pen.setWidth(5);                    // 设置线宽为5像素pen.setColor(QColor(200, 100, 50)); // 设置颜色为RGB值//pen.setColor(QColor("#888888"));   // 也可以使用十六进制颜色值// 创建并设置画刷QBrush brush(QColor(200, 100, 50)); // 创建纯色画刷///* brush.setColor(QColor(200, 100, 50));*/ // 注释掉的代码,设置画刷颜色// 将画笔给画家painter.setPen(pen);// 将画刷给画家(这行被注释掉了)// painter.setBrush(brush);// 绘制矩形painter.drawRect(200, 100, 100, 100); // 左上角(200, 100),宽100,高100// 绘制多边形(三角形)QPolygon polygon;polygon.setPoints(3, 100, 20, 200, 50, 300, 300); // 设置三个点的坐标painter.drawPolygon(polygon);// 绘制直线painter.drawLine(400, 400, 500, 500); // 从(400, 400)到(500, 500)的线// 绘制椭圆painter.drawEllipse(200, 200, 50, 100); // 中心(200, 200),宽50,高100// 绘制文本QRectF rectF(0, 0, 200, 100); // 文本区域painter.drawText(rectF, Qt::AlignHCenter, "正点原子"); // 水平居中对齐// 绘制路径QPainterPath path;path.moveTo(20, 80);                  // 移动到起点path.lineTo(20, 30);                  // 添加直线path.cubicTo(80, 0, 50, 50, 80, 80);  // 添加三次贝塞尔曲线painter.drawPath(path);               // 绘制路径
}

4.3 主函数 (main.cpp)

#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

4.4 项目文件 (45.pro)

QT       += core guigreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

5. 高级绘图技术

5.1 双缓冲绘图

双缓冲绘图可以避免闪烁,特别是在复杂绘图或动画中。

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);// 创建一个与窗口大小相同的QPixmapQPixmap pixmap(size());pixmap.fill(Qt::white);  // 填充白色背景// 在QPixmap上绘图QPainter painter(&pixmap);painter.setRenderHint(QPainter::Antialiasing);// 执行绘图操作...painter.drawRect(100, 100, 200, 150);painter.drawEllipse(150, 150, 100, 100);// 结束在QPixmap上的绘图painter.end();// 将QPixmap绘制到窗口上QPainter widgetPainter(this);widgetPainter.drawPixmap(0, 0, pixmap);
}

5.2 渐变填充

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 线性渐变QLinearGradient linearGradient(0, 0, 400, 0);  // 水平渐变linearGradient.setColorAt(0, Qt::red);         // 起点颜色linearGradient.setColorAt(0.5, Qt::yellow);    // 中点颜色linearGradient.setColorAt(1, Qt::blue);        // 终点颜色painter.setBrush(QBrush(linearGradient));painter.drawRect(50, 50, 400, 100);// 辐射渐变QRadialGradient radialGradient(300, 250, 100);  // 中心(300, 250),半径100radialGradient.setColorAt(0, Qt::white);        // 中心颜色radialGradient.setColorAt(1, Qt::green);        // 边缘颜色painter.setBrush(QBrush(radialGradient));painter.drawEllipse(200, 150, 200, 200);// 锥形渐变QConicalGradient conicalGradient(500, 250, 0);  // 中心(500, 250),起始角度0conicalGradient.setColorAt(0, Qt::red);conicalGradient.setColorAt(0.25, Qt::yellow);conicalGradient.setColorAt(0.5, Qt::green);conicalGradient.setColorAt(0.75, Qt::blue);conicalGradient.setColorAt(1, Qt::red);painter.setBrush(QBrush(conicalGradient));painter.drawEllipse(400, 150, 200, 200);
}

5.3 图像效果

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);// 加载图像QImage image("example.png");// 应用不透明度painter.setOpacity(0.5);  // 50%不透明度painter.drawImage(10, 10, image);// 恢复完全不透明painter.setOpacity(1.0);// 应用组合模式painter.setCompositionMode(QPainter::CompositionMode_Multiply);painter.drawImage(220, 10, image);// 恢复默认组合模式painter.setCompositionMode(QPainter::CompositionMode_SourceOver);// 应用图像变换QImage transformed = image.scaled(200, 150, Qt::KeepAspectRatio, Qt::SmoothTransformation);painter.drawImage(430, 10, transformed);
}

5.4 剪切区域

void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 创建剪切路径QPainterPath clipPath;clipPath.addEllipse(100, 100, 200, 200);  // 椭圆形剪切区域// 应用剪切路径painter.setClipPath(clipPath);// 在剪切区域内绘图// 只有在椭圆内的部分会被显示painter.fillRect(50, 50, 300, 300, Qt::blue);// 重置剪切区域painter.setClipping(false);// 在整个窗口绘图painter.setPen(QPen(Qt::red, 2));painter.drawRect(50, 50, 300, 300);
}

6. 动画绘图

6.1 使用定时器实现动画

// 在widget.h中添加
private:QTimer *timer;int angle;private slots:void updateAnimation();// 在widget.cpp的构造函数中添加
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), angle(0)
{ui->setupUi(this);// 创建定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &Widget::updateAnimation);timer->start(50);  // 每50毫秒更新一次
}// 添加更新函数
void Widget::updateAnimation()
{angle = (angle + 5) % 360;  // 增加角度,并保持在0-359范围内update();  // 触发重绘
}// 修改paintEvent
void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 移动到窗口中心painter.translate(width() / 2, height() / 2);// 旋转坐标系painter.rotate(angle);// 绘制旋转的矩形painter.setPen(QPen(Qt::blue, 2));painter.drawRect(-50, -50, 100, 100);
}

6.2 使用QPropertyAnimation实现动画

// 在widget.h中添加
#include <QPropertyAnimation>private:QPropertyAnimation *animation;QRect rectPosition;// 在widget.cpp的构造函数中添加
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), rectPosition(50, 50, 100, 100)
{ui->setupUi(this);// 创建属性动画animation = new QPropertyAnimation(this, "rectPosition");animation->setDuration(2000);  // 2秒animation->setStartValue(QRect(50, 50, 100, 100));animation->setEndValue(QRect(width() - 150, height() - 150, 100, 100));animation->setEasingCurve(QEasingCurve::OutBounce);  // 弹跳效果animation->setLoopCount(-1);  // 无限循环animation->start();
}// 添加属性访问器
QRect Widget::getRectPosition() const
{return rectPosition;
}void Widget::setRectPosition(const QRect &rect)
{rectPosition = rect;update();  // 触发重绘
}// 修改paintEvent
void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 绘制动画矩形painter.setPen(QPen(Qt::blue, 2));painter.setBrush(QBrush(Qt::yellow));painter.drawRect(rectPosition);
}

7. 性能优化技巧

7.1 减少重绘区域

// 只更新需要重绘的区域,而不是整个窗口
void Widget::updateSpecificArea()
{// 只更新矩形区域update(100, 100, 200, 200);// 或者使用QRegion更新复杂区域QRegion region(100, 100, 100, 100, QRegion::Ellipse);update(region);
}

7.2 使用缓存

// 在widget.h中添加
private:QPixmap cachedBackground;bool backgroundDirty;// 在构造函数中初始化
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget), backgroundDirty(true)
{ui->setupUi(this);
}// 在resizeEvent中处理缓存
void Widget::resizeEvent(QResizeEvent *event)
{Q_UNUSED(event);backgroundDirty = true;  // 窗口大小改变时,标记缓存为脏
}// 在paintEvent中使用缓存
void Widget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);// 如果缓存为脏或不存在,重新创建if (backgroundDirty || cachedBackground.isNull()) {cachedBackground = QPixmap(size());cachedBackground.fill(Qt::white);QPainter cachePainter(&cachedBackground);cachePainter.setRenderHint(QPainter::Antialiasing);// 绘制复杂的静态背景drawComplexBackground(&cachePainter);backgroundDirty = false;}// 绘制缓存的背景painter.drawPixmap(0, 0, cachedBackground);// 绘制动态内容drawDynamicContent(&painter);
}

7.3 避免不必要的绘图操作

void Widget::paintEvent(QPaintEvent *event)
{// 获取需要重绘的区域QRegion region = event->region();QPainter painter(this);// 只有当区域包含特定部分时才绘制if (region.intersects(QRect(100, 100, 200, 200))) {// 绘制第一部分drawFirstPart(&painter);}if (region.intersects(QRect(300, 300, 200, 200))) {// 绘制第二部分drawSecondPart(&painter);}
}

8.3 绘图质量问题

问题:绘制的图形边缘锯齿明显。

解决方案

  1. 启用抗锯齿:painter.setRenderHint(QPainter::Antialiasing);
  2. 使用浮点精度的坐标(QPointF、QRectF等)
  3. 对于文本,启用文本抗锯齿:painter.setRenderHint(QPainter::TextAntialiasing);
http://www.xdnf.cn/news/20304.html

相关文章:

  • 北斗导航 | 导航定位中的卡尔曼滤波算法:原理、公式及C代码详解
  • XXL-JOB基本使用
  • MyBatis高频问题-动态sql
  • 计算机网络:以太网中的数据传输
  • golang连接influxdb的orm操作
  • halcon-亚像素边缘提取教程
  • PyTorch 模型文件介绍
  • element-plus 表单校验-表单中包含多子组件表单的校验
  • (数据结构)哈希碰撞:线性探测法 vs 拉链法
  • 基于区块链的IoMT跨医院认证系统:Python实践分析
  • Flink中的事件时间、处理时间和摄入时间
  • Joplin-解决 Node.js 中 “digital envelope routines::unsupported“ 错误
  • 自旋锁/互斥锁 设备树 iic驱动总线 day66 67 68
  • 输入2.2V~16V 最高输出20V2.5A DCDC升压芯片MT3608L
  • 计算机网络:网络设备在OSI七层模型中的工作层次和传输协议
  • 鸿蒙 BLE 蓝牙智能设备固件升级之DFU升级方式(Nordic芯片)
  • macbook intel 打开cursor会闪退
  • MySQL集群高可用架构(MHA高可用架构)
  • Process Explorer进阶(第三章3.3):深入理解进程详情
  • [Windows] AdGuard.v7.21.5089.0 中文直装电脑版
  • cds序列转换为pepperl脚本详细解读及使用
  • Python多线程编程全面指南
  • web自动化测试
  • Elasticsearch优化从入门到精通
  • 线代:排列与逆序
  • 从机器学习的角度实现 excel 中趋势线:揭秘梯度下降过程
  • PageHelper的使用及底层原理
  • WordPress如何绑定多个域名 WordPress实现多域名访问
  • 新的打卡方式
  • GPIO介绍