本文分析了 QT 的 paint system,详细介绍了构成 paint system 的三个类:QPainter, QPainterEngine, QPaintDevice。
     

    简介1

QT 的 Paint System 主要是基于 QPainter, QPainterDevice 和 QPaintEngine 三个类。
QPainter 用于完成绘制操作。
QPaintDevice 是一个二维抽象空间,QPainter 在这个空间中绘制。
QPaintEngine 提供了接口,painter 使用这些接口往不同类型的 device 上绘制。QPaintEngine 只供 QPainter 和 QPaintDevice 在内部使用。除非创建自定义设备,应用程序开发人员不会用到 QPaintEngine。
来自资料1
来自资料1
      
      在这种设计思想下,所有的绘制基于相同的绘制管道,这样易于增加新特征,并且方便为不支持的特性提供默认实现。
三个类的详细 UML 类图如下所示:
从上图可以看出 QPaintEngine 和 QPainter 都有 XXXPrivate 对象,如 QPainterPrivate 和 QPaintEnginePrivate。这种 Private 实现是在 QT 中经常使用的设计方法,他用于分离平台相关的代码。所有平台共有的接口放在原始类中,各个平台独有的属性和方法在 private 类中实现。原始类包含 private 类的指针。

Paint Device

QPaintDevice 是所有可绘制对象的基类,QPainter 可以往任何 QPaintDevice 子类上绘制。目前 QPaintDevice 包括如下子类:QWidget, QImage, QPixmap, QGLWidget, QGLPixelBuffer, QPicture 和 QPrinter 。如下图所示。
来自资料1
来自资料1
Widget
QWidget 是所有 user interface 对象的基类,它接收来自鼠标、键盘、窗口的事件,把 user interface 对象绘制在屏幕上。
Image
QImage 类提供了一个硬件独立的 image 表示,它针对 I/O 作了优化,提供直接像素访问和操作功能。QImage 支持如下几种格式:monochrome, 8-bit, 32-bit 和 alpha-blended images。使用 QImage 作为绘制设备有如下优点:
  • 独立于任何硬件平台,保证绘制操作的 pixel exactness;
  • 绘制可以在当前 GUI 线程之外的令一个线程中完成。
Pixmap
QPixmap 是一个 off-screen image 表示,它为了在屏幕上显示 image 而设计并做了优化。与 QImage 不同,pixmap 中的数据是内部数据,由 window system 管理,像素只能通过 QPainter 接口访问,或者把 QPixmap 转换成 QImage 处理。
为了优化 QPixmap 上的绘制操作,QT 提供了 QPixmapCache 类缓存 pixmap 数据。
Qt 也提供了 QBitmap convenience 类,该类从 QPixmap 继承而来。 QBitmap 是 monochrome (1-bit depth) pixmaps,主要用于创建自定义 QCursor、 QBrush 对象等等。
OpenGL Widget
使用 QGLWidget 可以在 QT 应用中使用 OpenGL API 进行渲染。同时, QGLWidget 也是 QWidget 的子类,QPainter 可以使用它在任意 paint device 上绘制。这样设计的一大优点是它可以使 QT 使用 OpenGL 完成高性能的绘制操作,如 transformations, pixmap drawing 等。
Pixel Buffer
QGLPixelBuffer 类从 QPaintDevice 直接继承而来,它封装了一个 OpenGL pbuffer。往 pbuffer 里绘制通常完全使用硬件加速,与往 QPixmap 绘制比性能有显著提高。
Picture
QPicture 类是一个记录和执行 QPainter 命令的 painter device。Picture 将 painter 命令以平台独立的格式串行化到一个 IO 设备。同时 QPicture 也是分辨率独立的,可以在不同的设备上显示,如 svg, pdf, ps, printer,screen 等,效果看起来都是一致的。
Printer
QPrinter 是一个往打印机上绘制的设备。在 Windows 或者 Max OS X 平台上, QPrinter 使用内置的 printer 驱动程序。在 X11 平台上,QPrinter 生成 postscript,将它们发到 lpr, lp, 或者其它的打印程序。QPrinter 也可以打印到其它任意的 QPrintEngine 对象。
QPrinterEngine 类定义了一个 QPrinter 与指定打印子系统交互的接口。若定义自己的 print engine ,需要从 QPaintEngine 和 QPrintEngine 继承。
默认情况下,输出格式由 printer 所在的平台决定,也可以设置输出格式,如 PdfFormat。
定义自己的 QPaintDevice
另外,应用程序开发人员可以开发自己的 backend,定义自己的 QPaintDevice 的子类,重新实现 QPaintDevice::paintEngine() 方法告诉 QPainter 使用哪个 paint engine;基于 QPaintEngine 类实现自己的 paint engine。

Drawing

QPainter 提供了高度优化的函数实现绘制操作,既可以绘制简单的图元绘制 (QPoint, QLine, QRect, QRegion, QPolygon),也可以完成复杂的形状绘制,如 vector path。
线和轮廓使用 QPen 类绘制,pen 的属性包括:
  • style(如 line-type);
  • width;
  • brush;
  • how the endpoints are drawn,即 cap-style;
  • how joins between two connected lines,即 join-style;
brush 是一个 QBrush 对象,用于填充区域,QBrush 类同时定义了填充模式。
QPainter 也可以绘制文本和 pixmap。
当绘制文本时,字体使用 QFont 指定。QT 优先使用指定的字体,如果没有匹配的字体,QT 使用最近匹配的字体。实际使用的字体属性使用 QFontInfo 类查询。另外,QFontMetrics 类提供了字体尺寸信息,QFontDatabase 提供了系统中已安装的字体信息。
通常情况下,QPainter 在"natural"坐标系统下绘制,使用 QMatrix 类可以实现在 view 和世界坐标转换。

Filling

形状用 QBrush 类填充。 brush 的属性包括颜色和填充样式。
QT 使用 QColor 类表示颜色,它支持 RGB, HSV 和 CMYK 等颜色模式。QColor 也支持 alpha 混合的轮廓和填充,QColor 是平台和设备独立的。
当创建一个新 widget 时,推荐使用 widget 调色板中的颜色,而尽量不要以硬编码方法使用颜色。QT 的所有 widget 都包含一个调色板,使用调色板绘制。 widget 的调色板使用 QPalette 类。
QT 的填充模式用枚举类型 QT::BrushStyle 定义。QT 还提供了 QGraient 类提供渐变填充。

Styling

QT 的内建 widget 使用 QStyle 类完成绘制操作。QStyle 是一个抽象基类,封装了 GUI 的 look and feel,可以使 widget 看起来与 native widget 一样的效果,或者定制 widget 的外观。
QT 提供了一系列 QStyle 子类,它模拟了不同平台的外观,如 QWindowsStyle, QMacStyle, QMotifStyle 等。这些 sytles 内建在 QtGui 库中,其它的 style 可以通过 QT 的插件机制提供。
绘制 style 元素的大多数函数有四个参数:
  • 一个枚举值,指出绘制什么图形元素;
  • 一个 QStyleOption 对象,指出如何绘制以及往哪里绘制;
  • 一个 QPaiter 对象,用户绘制元素;
  • 一个 QWidget 对象,指出往哪里绘制,该参数可以不指定。