一、Qt绘图系统概述

说到Qt绘图系统,我得先跟你聊聊它的定位。

Qt绘图系统,说白了就是一套让你能在屏幕上「画东西」的框架。你想想看,不管是自定义控件、图表展示,还是游戏界面,最终都要落实到「怎么画出来」这个问题上。Qt把这套能力封装得相当优雅,我用了这么多年,真心觉得它设计得漂亮。

1.1 什么是Qt绘图系统

Qt绘图系统是一套基于QPainter的2D图形渲染框架。它不依赖任何第三方图形库,完全基于Qt自身实现。你可以在任何QPaintDevice上绘制——无论是窗口、图片,还是打印机。

我记得刚接触Qt时,有个困惑:为什么Qt不直接用OpenGL或者DirectX?后来才明白,Qt绘图系统追求的是跨平台一致性。你在Windows上画一个圆,到了macOS上还是那个圆,像素级一致。这一点,在实际项目中太重要了。

核心特点:

  • 纯软件渲染,不依赖GPU(当然也可以结合OpenGL)
  • 跨平台绘制结果一致
  • 支持反锯齿、渐变、透明度等高级效果
  • 与Qt事件系统、布局系统无缝集成

1.2 绘图系统的三大核心组件

Qt绘图系统由三个核心类构成,它们各司其职,配合默契。我习惯把它们比作「画家、画布和画笔引擎」。

组件 类名 角色
画家 QPainter 执行绘制操作
画布 QPaintDevice 提供绘制表面
画笔引擎 QPaintEngine 底层渲染实现

QPainter — 画家

QPainter是你要直接打交道的类。它提供了所有绘制接口:画线、画矩形、画圆、画文字、画路径……基本上你能想到的2D图形,它都有。

我个人的习惯是:永远在paintEvent()里创建QPainter。别在别的地方用,否则你会遇到各种奇怪的绘制问题。

小技巧:QPainter的状态机设计很巧妙。你可以用save()/restore()来保存和恢复绘制状态,比如画笔颜色、变换矩阵等。这在绘制复杂图形时特别有用。

QPaintDevice — 画布

QPaintDevice是所有可绘制对象的基类。常见的子类有:

  • QWidget — 窗口和控件
  • QPixmap — 屏幕优化过的图像
  • QImage — 独立于硬件的图像,支持像素级操作
  • QPicture — 记录和回放绘制命令
  • QPrinter — 打印机

这里有个坑,我曾经踩过:QPixmap和QImage看起来差不多,但QPixmap是存储在显存里的,适合频繁绘制;QImage在内存里,适合像素操作。如果你要逐像素修改图像,用QImage;如果只是显示,用QPixmap。

QPaintEngine — 画笔引擎

QPaintEngine是底层实现,你一般不会直接用它。它负责把QPainter的绘制命令转换成具体的图形输出。不同的QPaintDevice对应不同的引擎实现。

嗯,这里要注意:不要直接调用QPaintEngine的方法。它是内部实现细节,Qt官方也不保证API稳定。我见过有人为了性能直接操作引擎,结果Qt升级后代码全废了。

1.3 绘图的基本流程

搞清楚了组件,咱们来看看绘图到底怎么走。流程其实很简单,就三步:

  1. 创建QPainter对象,绑定到QPaintDevice上
  2. 调用绘制方法,比如drawRect()、drawText()
  3. 销毁QPainter对象,结束绘制

看个最简单的例子:

void MyWidget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);  // 第一步:创建画家,绑定到当前窗口
    
    painter.setPen(Qt::blue);        // 设置蓝色画笔
    painter.setBrush(Qt::yellow);    // 设置黄色画刷
    painter.drawRect(50, 50, 200, 100);  // 第二步:画矩形
    
    painter.drawText(100, 100, "Hello Qt");  // 画文字
    
    // 第三步:painter析构,自动结束绘制
}

你可能会问:为什么非要析构才结束?因为QPainter的构造函数里会调用begin(),析构函数里会调用end()。end()会做一些清理工作,比如刷新缓冲区。如果你手动调用begin()/end(),也可以,但我建议直接用RAII方式——让对象生命周期管理绘制周期。

警告:千万不要在paintEvent()之外创建QPainter并绘制到QWidget上。这会导致绘制不可控,甚至程序崩溃。我曾经在定时器里直接画,结果界面闪烁得跟迪斯科一样。

1.4 知识体系总览

为了让你对本章内容有个整体印象,我画了张图:

Qt绘图系统知识体系 三大核心组件 QPainter 画家:执行绘制操作 QPaintDevice 画布:提供绘制表面 QPaintEngine 引擎:底层渲染实现 绘制基本流程 ① 创建QPainter 绑定到QPaintDevice ② 调用绘制方法 drawRect/drawText等 ③ 销毁QPainter 自动调用end()清理 QPainter + QPaintDevice + QPaintEngine 三位一体

这张图把本章的核心内容串起来了。左边是三大组件,右边是绘制流程。你记住这个结构,后面学起来就清晰多了。

1.5 避坑指南

最后,分享几个我实际项目中遇到的坑:

我曾经犯过的错:

  • 在非UI线程里调用QPainter绘制QWidget — 界面直接崩了。记住:QPainter只能在GUI线程使用。
  • 忘记调用QPainter::end()就重复begin() — 会触发断言失败。用RAII方式能避免。
  • 在paintEvent()里new QPainter但不delete — 内存泄漏。用栈对象最安全。

好了,第一章就到这里。Qt绘图系统其实不复杂,核心就是理解那三个组件怎么配合。你把这个搞懂了,后面学具体绘制技巧就水到渠成。

可可精品资料库