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

Qt C++ 图形绘制完全指南:从基础到进阶实战

Qt C++ 图形绘制完全指南:从基础到进阶实战

前言

Qt框架提供了强大的2D图形绘制能力,通过QPainter类及其相关组件,开发者可以轻松实现各种复杂的图形绘制需求。本文将系统介绍Qt图形绘制的核心技术,并通过实例代码演示各种绘制技巧。

一、Qt图形绘制基础架构

1.1 核心类介绍

Qt图形绘制主要涉及以下核心类:

  • QPainter:执行绘制操作的主要类
  • QPaintDevice:绘制设备的抽象基类
  • QPaintEngine:定义QPainter如何在特定平台绘制
  • QWidget:最常用的绘制设备
  • QPixmap/QImage:图像绘制设备

1.2 绘制系统架构图

┌─────────────┐
│  QPainter   │ ← 绘制工具
└──────┬──────┘│
┌──────▼──────┐
│QPaintDevice │ ← 绘制表面
└──────┬──────┘│
┌──────▼──────┐
│QPaintEngine │ ← 底层引擎
└─────────────┘

二、基础图形绘制实战

2.1 创建自定义绘制Widget

首先创建一个自定义Widget类,重写paintEvent方法:

DrawWidget.h

#ifndef DRAWWIDGET_H
#define DRAWWIDGET_H#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QTimer>
#include <cmath>class DrawWidget : public QWidget
{Q_OBJECTpublic:explicit DrawWidget(QWidget *parent = nullptr);protected:void paintEvent(QPaintEvent *event) override;private slots:void updateAnimation();private:int m_animationAngle;QTimer *m_timer;void drawBasicShapes(QPainter &painter);void drawGradients(QPainter &painter);void drawTransformations(QPainter &painter);void drawPath(QPainter &painter);void drawText(QPainter &painter);
};#endif // DRAWWIDGET_H

DrawWidget.cpp

#include "DrawWidget.h"
#include <QLinearGradient>
#include <QRadialGradient>
#include <QPainterPath>
#include <QFont>DrawWidget::DrawWidget(QWidget *parent) : QWidget(parent), m_animationAngle(0)
{setFixedSize(800, 600);setWindowTitle("Qt图形绘制示例");// 设置定时器用于动画m_timer = new QTimer(this);connect(m_timer, &QTimer::timeout, this, &DrawWidget::updateAnimation);m_timer->start(50); // 20 FPS
}void DrawWidget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);// 设置白色背景painter.fillRect(rect(), Qt::white);// 绘制各种图形drawBasicShapes(painter);drawGradients(painter);drawTransformations(painter);drawPath(painter);drawText(painter);
}void DrawWidget::drawBasicShapes(QPainter &painter)
{painter.save();// 绘制标题painter.setPen(QPen(Qt::black, 2));painter.setFont(QFont("Arial", 12, QFont::Bold));painter.drawText(20, 30, "基础图形绘制");// 设置画笔和画刷QPen pen(Qt::blue, 3, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);painter.setPen(pen);// 绘制直线painter.drawLine(50, 50, 150, 50);// 绘制矩形painter.setBrush(QBrush(Qt::yellow, Qt::SolidPattern));painter.drawRect(50, 70, 100, 60);// 绘制圆角矩形painter.setBrush(QBrush(Qt::cyan, Qt::Dense4Pattern));painter.drawRoundedRect(170, 70, 100, 60, 15, 15);// 绘制椭圆painter.setBrush(QBrush(Qt::magenta, Qt::DiagCrossPattern));painter.drawEllipse(290, 70, 100, 60);// 绘制多边形QPolygon polygon;polygon << QPoint(420, 70) << QPoint(470, 70) << QPoint(495, 100) << QPoint(470, 130) << QPoint(420, 130) << QPoint(395, 100);painter.setBrush(QBrush(Qt::green, Qt::CrossPattern));painter.drawPolygon(polygon);// 绘制弧形painter.setBrush(Qt::NoBrush);painter.setPen(QPen(Qt::red, 3));painter.drawArc(520, 70, 80, 60, 30 * 16, 120 * 16);// 绘制扇形painter.setBrush(QBrush(Qt::darkCyan));painter.drawPie(620, 70, 80, 60, 45 * 16, 90 * 16);painter.restore();
}void DrawWidget::drawGradients(QPainter &painter)
{painter.save();// 绘制标题painter.setPen(QPen(Qt::black, 2));painter.setFont(QFont("Arial", 12, QFont::Bold));painter.drawText(20, 180, "渐变效果");// 线性渐变QLinearGradient linearGrad(50, 200, 150, 260);linearGrad.setColorAt(0, Qt::red);linearGrad.setColorAt(0.5, Qt::yellow);linearGrad.setColorAt(1, Qt::green);painter.setBrush(linearGrad);painter.drawRect(50, 200, 100, 60);// 径向渐变QRadialGradient radialGrad(220, 230, 50);radialGrad.setColorAt(0, Qt::white);radialGrad.setColorAt(0.5, Qt::cyan);radialGrad.setColorAt(1, Qt::blue);painter.setBrush(radialGrad);painter.drawEllipse(170, 200, 100, 60);// 锥形渐变QConicalGradient conicalGrad(320, 230, 0);conicalGrad.setColorAt(0, Qt::red);conicalGrad.setColorAt(0.25, Qt::yellow);conicalGrad.setColorAt(0.5, Qt::green);conicalGrad.setColorAt(0.75, Qt::blue);conicalGrad.setColorAt(1, Qt::red);painter.setBrush(conicalGrad);painter.drawEllipse(290, 200, 60, 60);painter.restore();
}void DrawWidget::drawTransformations(QPainter &painter)
{painter.save();// 绘制标题painter.setPen(QPen(Qt::black, 2));painter.setFont(QFont("Arial", 12, QFont::Bold));painter.drawText(20, 310, "变换效果(动画)");// 保存原始状态painter.save();// 平移到旋转中心painter.translate(100, 360);// 应用旋转(动画)painter.rotate(m_animationAngle);// 绘制旋转的矩形painter.setBrush(QBrush(Qt::darkBlue));painter.drawRect(-30, -20, 60, 40);painter.restore();// 缩放效果painter.save();painter.translate(220, 360);double scale = 1.0 + 0.5 * sin(m_animationAngle * M_PI / 180.0);painter.scale(scale, scale);painter.setBrush(QBrush(Qt::darkGreen));painter.drawEllipse(-30, -30, 60, 60);painter.restore();// 错切效果painter.save();painter.translate(340, 360);painter.shear(0.5 * sin(m_animationAngle * M_PI / 180.0), 0);painter.setBrush(QBrush(Qt::darkRed));painter.drawRect(-30, -20, 60, 40);painter.restore();painter.restore();
}void DrawWidget::drawPath(QPainter &painter)
{painter.save();// 绘制标题painter.setPen(QPen(Qt::black, 2));painter.setFont(QFont("Arial", 12, QFont::Bold));painter.drawText(20, 440, "路径绘制");// 创建复杂路径QPainterPath path;path.moveTo(50, 460);path.lineTo(100, 460);path.cubicTo(120, 440, 140, 480, 160, 460);path.lineTo(200, 460);path.quadTo(220, 480, 240, 460);path.arcTo(240, 440, 40, 40, 0, 180);// 绘制路径painter.setPen(QPen(Qt::darkMagenta, 3));painter.setBrush(QBrush(Qt::lightGray));painter.drawPath(path);// 创建星形路径QPainterPath starPath;int starX = 400, starY = 470;for (int i = 0; i < 5; ++i) {double angle = i * 72 * M_PI / 180.0 - M_PI / 2;double x = starX + 30 * cos(angle);double y = starY + 30 * sin(angle);if (i == 0) {starPath.moveTo(x, y);} else {starPath.lineTo(x, y);}angle = (i * 72 + 36) * M_PI / 180.0 - M_PI / 2;x = starX + 15 * cos(angle);y = starY + 15 * sin(angle);starPath.lineTo(x, y);}starPath.closeSubpath();painter.setPen(QPen(Qt::darkYellow, 2));painter.setBrush(QBrush(Qt::yellow));painter.drawPath(starPath);painter.restore();
}void DrawWidget::drawText(QPainter &painter)
{painter.save();// 绘制标题painter.setPen(QPen(Qt::black, 2));painter.setFont(QFont("Arial", 12, QFont::Bold));painter.drawText(20, 540, "文字绘制");// 普通文字painter.setFont(QFont("Times New Roman", 14));painter.setPen(Qt::darkBlue);painter.drawText(50, 565, "Hello Qt Graphics!");// 带阴影的文字painter.setFont(QFont("Arial", 16, QFont::Bold));painter.setPen(Qt::gray);painter.drawText(202, 567, "Shadow Text");painter.setPen(Qt::black);painter.drawText(200, 565, "Shadow Text");// 旋转文字painter.save();painter.translate(400, 560);painter.rotate(-30);painter.setFont(QFont("Courier", 14));painter.setPen(Qt::darkGreen);painter.drawText(0, 0, "Rotated Text");painter.restore();// 渐变文字QLinearGradient textGrad(500, 550, 600, 570);textGrad.setColorAt(0, Qt::blue);textGrad.setColorAt(1, Qt::red);painter.setPen(QPen(QBrush(textGrad), 2));painter.setFont(QFont("Arial", 18, QFont::Bold));painter.drawText(500, 565, "Gradient");painter.restore();
}void DrawWidget::updateAnimation()
{m_animationAngle = (m_animationAngle + 5) % 360;update(); // 触发重绘
}

2.2 主窗口实现

main.cpp

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

三、高级绘制技术

3.1 双缓冲绘制

为了避免闪烁,Qt默认启用双缓冲。也可以手动实现:

void CustomWidget::paintEvent(QPaintEvent *event)
{QPixmap pixmap(size());pixmap.fill(Qt::white);QPainter pixmapPainter(&pixmap);pixmapPainter.setRenderHint(QPainter::Antialiasing);// 在pixmap上绘制drawContent(pixmapPainter);// 将pixmap绘制到widgetQPainter widgetPainter(this);widgetPainter.drawPixmap(0, 0, pixmap);
}

3.2 图形项框架 (Graphics View Framework)

对于复杂的图形场景,使用Graphics View框架更合适:

// 场景图形项
class CustomItem : public QGraphicsItem
{
public:CustomItem(){setFlag(ItemIsMovable);setFlag(ItemIsSelectable);}QRectF boundingRect() const override{return QRectF(-50, -50, 100, 100);}void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,QWidget *widget) override{Q_UNUSED(option);Q_UNUSED(widget);painter->setBrush(isSelected() ? Qt::yellow : Qt::lightBlue);painter->setPen(QPen(Qt::black, 2));painter->drawEllipse(boundingRect());}
};// 使用场景
QGraphicsScene *scene = new QGraphicsScene();
scene->addItem(new CustomItem());QGraphicsView *view = new QGraphicsView(scene);
view->setRenderHint(QPainter::Antialiasing);
view->show();

3.3 OpenGL集成

Qt支持OpenGL绘制,可以实现高性能3D图形:

class OpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
protected:void initializeGL() override{initializeOpenGLFunctions();glClearColor(0.0f, 0.0f, 0.0f, 1.0f);}void paintGL() override{glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// OpenGL绘制代码}void resizeGL(int w, int h) override{glViewport(0, 0, w, h);}
};

四、性能优化技巧

4.1 绘制优化策略

  1. 减少重绘区域
void Widget::updatePartial()
{// 只更新特定区域update(QRect(10, 10, 100, 100));
}
  1. 使用绘制缓存
class CachedWidget : public QWidget
{
private:QPixmap m_cache;bool m_cacheValid = false;protected:void paintEvent(QPaintEvent *event) override{if (!m_cacheValid) {m_cache = QPixmap(size());QPainter cachePainter(&m_cache);drawComplexContent(cachePainter);m_cacheValid = true;}QPainter painter(this);painter.drawPixmap(0, 0, m_cache);}
};
  1. 批量绘制操作
// 低效方式
for (int i = 0; i < 1000; ++i) {painter.drawPoint(points[i]);
}// 高效方式
painter.drawPoints(points.data(), 1000);

4.2 渲染提示设置

painter.setRenderHint(QPainter::Antialiasing, true);        // 抗锯齿
painter.setRenderHint(QPainter::TextAntialiasing, true);    // 文字抗锯齿
painter.setRenderHint(QPainter::SmoothPixmapTransform, true); // 平滑变换

五、实战案例:自定义图表控件

5.1 简单饼图实现

class PieChart : public QWidget
{
private:QVector<QPair<QString, double>> m_data;QVector<QColor> m_colors;public:void setData(const QVector<QPair<QString, double>> &data){m_data = data;generateColors();update();}protected:void paintEvent(QPaintEvent *event) override{Q_UNUSED(event);QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);QRect pieRect = rect().adjusted(20, 20, -20, -20);double total = 0;for (const auto &item : m_data) {total += item.second;}int startAngle = 0;for (int i = 0; i < m_data.size(); ++i) {int spanAngle = static_cast<int>(m_data[i].second / total * 360 * 16);painter.setBrush(m_colors[i]);painter.drawPie(pieRect, startAngle, spanAngle);startAngle += spanAngle;}}private:void generateColors(){m_colors.clear();for (int i = 0; i < m_data.size(); ++i) {m_colors.append(QColor::fromHsv(i * 360 / m_data.size(), 200, 200));}}
};

六、常见问题与解决方案

6.1 绘制闪烁问题

问题:快速更新时界面闪烁
解决方案

  • 启用双缓冲(Qt默认启用)
  • 使用setAttribute(Qt::WA_OpaquePaintEvent)
  • 避免在paintEvent中进行复杂计算

6.2 坐标系统混淆

问题:绘制位置不正确
解决方案

// 理解Qt坐标系统
// (0,0) 在左上角
// x轴向右增长
// y轴向下增长// 坐标变换
painter.translate(100, 100);  // 移动原点
painter.scale(2.0, 2.0);      // 缩放
painter.rotate(45);           // 旋转(顺时针)

6.3 性能问题

问题:绘制大量图形时卡顿
解决方案

  • 使用Graphics View框架
  • 实现图形项的LOD(细节层次)
  • 使用OpenGL加速
  • 裁剪不可见区域

七、最佳实践总结

  1. 合理选择绘制方式

    • 简单绘制:重写paintEvent
    • 复杂场景:Graphics View框架
    • 3D/高性能:OpenGL
  2. 性能优化原则

    • 最小化重绘区域
    • 缓存复杂绘制结果
    • 批量处理绘制操作
  3. 代码组织建议

    • 分离绘制逻辑和业务逻辑
    • 使用绘制状态的保存/恢复
    • 合理使用渲染提示

八、项目配置

.pro文件配置

QT += core gui widgetsCONFIG += c++11TARGET = QtGraphicsDemo
TEMPLATE = appSOURCES += \main.cpp \DrawWidget.cppHEADERS += \DrawWidget.h# 如果使用OpenGL
# QT += opengl

总结

本文系统介绍了Qt C++图形绘制的核心技术,从基础的QPainter使用到高级的Graphics View框架和OpenGL集成。通过实际代码示例,展示了各种绘制技巧和优化方法。掌握这些技术,可以开发出功能丰富、性能优异的图形应用程序。

Qt的图形系统非常强大和灵活,本文只是涵盖了最常用的部分。建议读者在实际项目中根据具体需求选择合适的技术方案,并持续关注Qt的最新特性和最佳实践。

参考资源

  • Qt官方文档 - Painting Classes
  • Qt Graphics View Framework
  • Qt OpenGL Integration

作者: Qt开发者
发布时间: 2024
标签: Qt, C++, 图形绘制, QPainter, Graphics View


文章转载自:

http://XrBrvYKN.nqbpz.cn
http://3qeJ6XIW.nqbpz.cn
http://g4W9y6n5.nqbpz.cn
http://3jNTGLN9.nqbpz.cn
http://uraf3q17.nqbpz.cn
http://asL0hOuV.nqbpz.cn
http://w6oXSPBN.nqbpz.cn
http://XYJC57bg.nqbpz.cn
http://XajgF4fL.nqbpz.cn
http://yjuW4I3y.nqbpz.cn
http://DQJgSBud.nqbpz.cn
http://q9sq80FP.nqbpz.cn
http://BHOrD2hx.nqbpz.cn
http://iogawQBM.nqbpz.cn
http://NJ6s51ry.nqbpz.cn
http://vqZ0wTZv.nqbpz.cn
http://T3snAQZr.nqbpz.cn
http://bYvTWHy3.nqbpz.cn
http://GxXebzkf.nqbpz.cn
http://NgrdOeqL.nqbpz.cn
http://wevl7Ujm.nqbpz.cn
http://y1px0bOm.nqbpz.cn
http://TeS1vux2.nqbpz.cn
http://QqAv0kiU.nqbpz.cn
http://XQVtbqbE.nqbpz.cn
http://ODVPvG4t.nqbpz.cn
http://ZmlMqN4j.nqbpz.cn
http://9Zh1kaRQ.nqbpz.cn
http://zxUKp7YA.nqbpz.cn
http://Zlo0fGa9.nqbpz.cn
http://www.dtcms.com/a/377010.html

相关文章:

  • 我在嘉顺达蓝海的安全坚守
  • fastadmin安装后后台提示putenv()报错,不显示验证码
  • macOS苹果电脑运行向日葵远程控制软件闪退
  • 平衡车 -- 倒立摆
  • 利用OpenCV实现模板与多个对象匹配
  • 机器学习的发展与应用:从理论到现实
  • 软考系统架构设计师之软件系统建模
  • leedcode 算法刷题第三十一天
  • IDEA下载安装图文教程(非常详细,适合新手)
  • Spark 性能优化全攻略:内存管理、shuffle 优化与参数调优
  • 老味道私房菜订餐系统的设计与实现(代码+数据库+LW)
  • 古董装载优化:30秒破解重量限制
  • Vue2手录02-指令
  • 爬虫逆向之瑞数6案例(深圳大学某某附属医院)
  • AWK工具使用与技巧指南
  • Java程序员职业发展路径与转型选择分析报告(2025年)
  • 资产管理软件哪家口碑好
  • 【实战中提升自己完结篇】分支篇之分支之无线、内网安全与QOS部署(完结)
  • 【Qt】PyQt、原生QT、PySide6三者的多方面比较
  • 多级缓存架构
  • 多模态对齐与多模态融合
  • 【MySQL】常用SQL语句
  • 教师节组诗-我不少年师已老,无报师恩仅遥忆
  • 手把手带你推导“逻辑回归”核心公式
  • 当按摩机器人“活了”:Deepoc具身智能如何重新定义人机交互体验
  • solidity得高级语法3
  • PLM 与机器视觉协同:三维模型驱动自动光学检测标准制定
  • vuecli中使用splitchunksplugin提取公共组件,vue单组件使用less scoped处理style,打包会有css顺序冲突警告
  • 元宇宙与旅游产业:沉浸式体验重构旅行全流程
  • 城市道路落叶清扫机设计【三维SW模型】【含9张CAD