目录
Public Types
Public Functions
Detailed Description
Settings
Drawing
Drawing Pixmaps and Images
Rendering Quality
Coordinate Transformations
Clipping
Composition Modes
Limitations
Performance
QPainter提供高度优化的函数完成绘制GUI项目的大部分请求。它可以绘制任何东西,从简单的线到复杂的形状如扇形和和弦。它也可以绘制对齐文本和像素映射图(像图)。通常它是在自然坐标系统中绘制,但是它也可以进行视图和世界转换。QPainter可以在任何继承自QPainterDevice类的对象上操作。
QPainter的常用用法是在控件的绘图事件中:构造并定制painter(如设置pen或brush),然后绘制。记得在绘制后将QPainter对象析构。例如:
void SimpleExampleWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setPen(Qt::blue);
painter.setFont(QFont("Arial", 30));
painter.drawText(rect(), Qt::AlignCenter, "Qt");
}
QPainter的核心功能是绘制,但是它也提供了几个函数允许你定制QPainter的配置和渲染质量以及使能剪切。此外你可以通过painter的组合模式指定不同形状如何融合在一起。
isActive()函数表明painter是否启用。painter通过begin()函数和构造器(带一个QPaintDevice参数)启用。通过end()函数和析构器使它关闭。
QPaintDevice,QPaintEngine和QPainter构成了Qt绘图系统的基础。QPainter是实现绘制操作的类。QPaintDevice呈现了一个可以用QPainter在上面绘制的设备。QPaintEngine提供接口,这些接口定义了painter在不同类型设备上如何绘制。如果painter是启用的,device()返回painter绘制在哪个绘图设备,paintEngine()返回painter当前操作的绘图引擎。更多信息请参考Paint System。
有时让其他人绘制在一个不寻常的QPaintDevice上也是能做到的。QPainter提供静态函数setRedirected()可以实现这个。
警告:当绘图设备是一个窗口,QPainter只能在paintEvent()函数或者在一个由paintEvent()调用的函数中使用。
有几个配置可以让你根据你的喜好定义QPainter绘制:
注意其中一些配置和一些绘图设备中的配置是镜像的,如QWidget::font()。QPainter::begin()函数(或者等价的QPainter构造器)会从绘图设备中拷贝这些属性。
可以在任何时候通过调用save()函数保存QPainter的状态,这些状态保存了内部堆栈上的所有可获得的配置。而restore()函数将他们弹出。
QPainter提供绘制大部分原语的函数:drawPoint(),drawPoints(),drawLine(),drawRect(), drawRoundedRect(), drawEllipse(), drawArc(), drawPie(), drawChord(), drawPolyline(), drawPolygon(), drawConvexPolygon() and drawCubicBezier()。两个便捷函数drawRects()和drawLines(),使用当前的笔和画刷按给定的QRects或QLines数组绘制对应数量的矩形或线。
QPainter类的fillRect()函数可以使用给定的QBrush填充给定的QRect。eraseRect()函数用于擦除指定矩形内的区域。
所有这些函数都有整型和浮点型版本。
Basic Drawing Example
Basic Drawing例子展示如何使用QPainter类在各种样式中显示基础的图形原语。
如果你需要绘制复杂的形状,特别是你需要重复时,考虑创建一个QPainterPath并用drawPath()绘制它。
Painter Paths example
QPainterPath类为绘制操作提供了一个容器,允许构造和重用图形形状。
Painter Paths例子展示painter paths如何用于构建复杂的形状进行渲染.
QPainter也提供了fillPath()函数来通过指定的QBrush填充指定的QPainterPath以及strokePath函数绘制指定路径的轮廓。
Vector Deformation例子展示如何使用高级向量技术绘制QPainterPath的文字,Gradients例子展示Qt里不同类型的渐变,Path Stroking例子展示Qt的短线模式以及展示自定义模式如何用于扩展模式范围。
使用drawText()可以进行文本绘制。当你需要细粒度的位置时,boundingRect()讲述指定drawText()命令将绘制在哪里。
有函数用于绘制pixmaps/images,名字为drawPixmap(), drawImage()和drawTiledPixmap()。除了drawPixmap()在屏幕上更快而drawImage()可能在QPrinter或其他设备上更快,drawPixmap()和drawImage()产生相同的结果。
有一个drawPicture()函数绘制整个QPicture的内容。它是唯一忽略所有painter设置的函数,因为QPicture有自己的设置。
Drawing High Resolution Versions of Pixmaps and Images
像图的高分辨率版本有一个比1大的设备像素比值(见QImageReader,QPixmap::devicePixelRatio())。如果它匹配底层QPaintDevice的值,它将直接绘制到设备上,而不应用额外的转换。
这是在高DPI屏幕上绘制一个64 × 64像素大小、设备像素比为2的QPixmap(设备像素比也为2)的例子。注意像图在用户空间是32x32像素。Qt中基于pixmap大小计算布局几何的代码路径将使用这个大小。这样做的净效果是像素图显示为高DPI像素图,而不是一个大的像素图。
为了使用QPainter获取最优渲染结果,你应该使用平台独立的QImage作为绘制设备;即使用QImage将确保在任何平台上都有理想的像素呈现效果。
QPainter类也提供一个控制渲染质量的方法,那就是通过他的RenderHint枚举及对浮点型精度的支持:所有绘制原语的函数都有一个浮点型版本。这些通常和QPainter::Antialiasing渲染模式一起使用。
Concentric Circles Example
Concentric Circles例子展示在绘制自定义控件时使用浮点精度和抗锯齿,能提高渲染质量。
应用的主窗口显示精度和抗锯齿的不同组合下绘制出来的控件效果。
RenderHint枚举表示QPainter的标志,一些引擎会遵守,一些引擎不会遵守。QPainter::Antialiasing表明如果可以的话,引擎应该抗锯齿原语的边缘。QPainter::TextAntialiasing表示如果可以的话,引擎应该抗锯齿文字,以及QPainter::SmoothPixmapTransform表明引擎应该使用平滑像图转换算法。
renderHints()函数返回指定painter设置的渲染提示。使用setRenderHint()函数设置或清空当前设置的RenderHints。
通常,QPainter操作在设备自己的坐标系统,但是QPainter对坐标转换有较好的支持。
最常用的转换时缩放,旋转,转置和剪切。使用scale()函数可以以指定比例进行缩放。rotate()和函数可以顺时针旋转,translate()可以转置(即添加指定的偏移到每个点)。你也可以使用shear()函数将坐标系统围绕原点扭转。查看Affine Transformations例子,那是一个剪切坐标系统的可视化。
另请参阅转换示例,该示例显示了转换如何影响QPainter呈现图形原语的方式。特别地,它显示了变换的顺序如何影响结果。
Affine Transformations Example
Affine Transformations示例展示了Qt在绘制操作上执行仿射转换的能力。演示还允许用户试验转换操作,并立即看到结果。
所有转换操作都在转换worldTransform()上操作。矩阵将平面上的一点变换为另一点。有关转换矩阵的更多信息,请参见坐标系统和QTransform文档。
setWorldTransform()函数可以替换或添加到当前设置的worldTransform()中。resetTransform()函数重置使用translate()、scale()、shear()、rotate()、setWorldTransform()、setViewport()和setWindow()函数所做的任何转换。deviceTransform()返回从逻辑坐标转换到依赖平台的绘图设备的设备坐标的矩阵。只有在平台相关句柄上使用平台绘制命令时才需要后一个函数,并且平台本身不执行转换。
当使用QPainter绘制时,我们使用逻辑坐标指定点,然后将逻辑坐标转换为绘制设备的物理坐标。逻辑坐标到物理坐标的映射由QPainter的combinedTransform()处理,这是viewport()和window()以及worldTransform()的组合。viewport()表示指定任意矩形的物理坐标,window()在逻辑坐标中描述相同的矩形,而worldTransform()与转换矩阵相同。
QPainter可以将任何绘制操作剪切到矩形,区域或者向量路径。当前剪辑可以用函数clipRegion()和clipPath()获取。路径还是区域更合适(更快)依赖于底层paintEngine()。例如,QImage绘图引擎更适合路径而X11绘图引擎更适合区域。设置剪辑是在painter逻辑坐标中完成的。
在QPainter的剪切后,绘图设备可能也剪切了。例如,大多数小部件会剪辑掉子部件使用的像素,大多数打印机会剪辑掉纸张边缘附近的区域。clipRegion()或hasClipping()的返回值没有反映这个额外的剪辑。
QPainter提供了CompositionMode枚举,它定义了数字图像合成的Porter-Duff规则;它描述了一种模型,用于将一个图像中的像素(源图像)与另一个图像中的像素(目标图像)相结合。
最常见的两种组合形式是Source和SourceOver。源用于将不透明的对象绘制到绘图设备上。在这种模式下,源中的每个像素替换目标中的相应像素。在SourceOver组合模式中,源对象是透明的,并绘制在目标的顶部。
请注意,合成转换是按像素进行的。由于这个原因,使用图形基元本身和它的边界矩形是有区别的:边界矩形包含alpha == 0的像素(即围绕基元的像素)。这些像素将覆盖其他图像的像素,有效地清除这些像素,而原语只覆盖它自己的区域。
Composition Modes Example
在Qt的示例目录中可以找到组合模式的例子,它允许你尝试各种组合模式并立即看到结果。
如果你使用Qt的基于栅格的绘制引擎的坐标,需要注意的是,当坐标大于+/- 215时可以使用,任何在这个范围之外的坐标执行的绘制都不能保证显示;这幅画可以剪掉。这是由于在实现中使用了short int。
Qt的描边器生成的轮廓在处理曲线形状时只是一种近似。在大多数情况下,不可能用另一个bezier曲线段来表示一个bezier曲线段的轮廓,因此Qt通过使用几个较小的曲线来逼近曲线轮廓。由于性能原因,Qt对这些轮廓使用的曲线数量是有限的,因此当使用较大的笔宽或比例时,轮廓错误会增加。要生成带有较小错误的轮廓,可以使用QPainterPathStroker类,它有setCurveThreshold成员函数,让用户指定错误容错性。另一个解决方法是先将路径转换为多边形,然后再绘制多边形。
QPainter是一个丰富的框架,允许开发人员进行各种图形操作,如渐变、组合模式和矢量图形。QPainter可以跨各种不同的硬件和软件堆栈实现这一功能。当然,硬件和软件的底层组合对性能有一些影响,并且确保每一个单独的操作在所有组合模式、笔刷、剪切、转换等的所有组合中都是快速的,这几乎是一个不可能的任务,因为排列的数量。作为一种妥协,我们选择了QPainter API和后端的一个子集,在这里性能保证与我们在给定的硬件和软件组合中所能得到的一样好。
作为高性能引擎,我们关注的后端是:
光栅-这个后端在纯软件中实现所有的渲染,总是用于渲染到QImages。为了优化性能,只能使用格式类型QImage:: format_argb32_pre相乘,QImage::Format_RGB32或QImage::Format_RGB16。任何其他格式,包括QImage::Format_ARGB32,性能明显更差。默认情况下,该引擎用于QWidget和QPixmap。
opengl2.0 (ES)——这个后端是硬件加速图形的主要后端。它可以在支持OpenGL 2.0或OpenGL/ES 2.0规范的台式机和嵌入式设备上运行。这包括过去几年生产的大多数图形芯片。引擎可以通过在QOpenGLWidget上使用QPainter来启用。
这些操作是:
简单的转换,意味着平移和缩放,加上0,90,180,270度的旋转。
drawPixmap()结合简单的变换和不透明的非平滑变换模式(QPainter::SmoothPixmapTransform没有作为渲染提示启用)。
矩形填充纯色,双色线性渐变和简单的变换。
矩形剪辑与简单的变换和交叉剪辑。
合成模式QPainter::CompositionMode_Source和QPainter::CompositionMode_SourceOver。
圆角矩形填充使用纯色和双色线性渐变填充。
通过qDrawBorderPixmap,有3x3个补丁的像素地图。
这个列表给出了在性能至关重要的应用程序中可以安全地使用哪些特性的指示。对于某些设置,其他操作可能也很快,但在广泛使用它们之前,建议在软件最终将运行的系统上对它们进行基准测试和验证。也有一些情况下,昂贵的操作是可以使用的,例如,当结果缓存在QPixmap。
官方文档:https://doc.qt.io/qt-5/qpainter.html