持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情
注:示例为Qt 5.1.1中的示例。
本文旨在剖析Qt示例的源码,总结函数使用方法以及编程思想,提高自己的编程能力。
示例运行效果:
文件目录:
具体实现:
RenderArea类:
设置属性函数:
使用setAntialiased()和setTransformed()槽函数,可以根据槽函数的参数改变属性的状态,并调用QWidget::update()槽函数,让改变后的属性在RenderArea小部件中可见。
paintEvent函数:
重新实现QWidget::paintEvent()函数。要做的第一件事是创建图形对象,通过paintEvent函数将绘制各种形状。
- 首先创建了一个4个qpoint的矢量。使用这个矢量来渲染点、折线和多边形形状。然后创建了一个QRect,在平面中定义一个矩形,使用它作为所有形状的边界矩形,不包括Path和Pixmap。
- 还创建了一个QPainterPath。QPainterPath类为绘制操作提供了一个容器,使图形形状能够被构造和重用。QPainterPath是由许多图形构建块组成的对象,如矩形、椭圆、直线和曲线。在这个例子中,创建了一个由一条直线和贝塞尔曲线组成的绘制路径。
- 还定义了一个起始角和一个弧长,将在绘制arc, Chord和Pie形状时使用。
为RenderArea小部件创建一个QPainter,并根据RenderArea的钢笔和笔刷设置画家的钢笔和笔刷。如果抗锯齿参数选项被选中,设置QPainter的渲染提示。
- 渲染RenderArea的形状的多个副本。副本的数量取决于RenderArea小部件的大小,这里使用了两个for循环和小部件的高度和宽度来计算它们的位置。
- 对于每个副本,首先保存当前的画家状态(将状态压入堆栈)。然后使用QPainter::translate()函数将坐标系统转换到由for循环变量决定的位置。如果省略了坐标系统的转换,所有形状的副本将会在RenderArea小部件的左上角相互叠加呈现。
- 如果选中了transforms参数选项,那么在使用QPainter::rotate()函数将坐标系顺时针旋转60度并使用QPainter::scale()函数将其缩小之前,要将对坐标系进行额外的转换。最后,将坐标系平移回旋转和缩放之前的位置。
- 当渲染这个形状时,它看起来就像在三维空间中旋转一样。
- 确定RenderArea的形状,并使用相关的QPainter绘图功能渲染它。
- 在开始渲染之前,保存了当前的绘制器状态(将状态压入堆栈)。这样做的基本原理是,计算每个形状副本相对于坐标系统中的同一点的位置。当转换坐标系时,除非在开始转换过程前保存当前的绘制状态,否则会失去这一点的知识。
- 然后,完成渲染形状的副本时,可以使用QPainter::restore()函数,用它的相关坐标系统恢复原始的画家状态。通过这种方式,确保了下一个形状副本将被渲染在正确的位置。
- 可以使用QPainter::translate()将坐标系统转换回来,而不是保存painter状态。但是,由于除了平移坐标系(当选中Transformation参数选项时)还旋转和缩放坐标系,最简单的解决方案是保存当前的画家状态。
一点感想:
在实现绘图时,一定要充分利用提供的一些现有的方法。