Qt示例 | 基本图型的绘制 Basic Drawing Example(四)

262 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

注:示例为Qt 5.1.1中的示例。
本文旨在剖析Qt示例的源码,总结函数使用方法以及编程思想,提高自己的编程能力。

示例运行效果:

1.gif

文件目录:

image.png

具体实现:

RenderArea类:

image.png

设置属性函数:

image.png

使用setAntialiased()和setTransformed()槽函数,可以根据槽函数的参数改变属性的状态,并调用QWidget::update()槽函数,让改变后的属性在RenderArea小部件中可见。

paintEvent函数:

image.png

重新实现QWidget::paintEvent()函数。要做的第一件事是创建图形对象,通过paintEvent函数将绘制各种形状。

  • 首先创建了一个4个qpoint的矢量。使用这个矢量来渲染点、折线和多边形形状。然后创建了一个QRect,在平面中定义一个矩形,使用它作为所有形状的边界矩形,不包括Path和Pixmap。
  • 还创建了一个QPainterPath。QPainterPath类为绘制操作提供了一个容器,使图形形状能够被构造和重用。QPainterPath是由许多图形构建块组成的对象,如矩形、椭圆、直线和曲线。在这个例子中,创建了一个由一条直线和贝塞尔曲线组成的绘制路径。
  • 还定义了一个起始角和一个弧长,将在绘制arc, Chord和Pie形状时使用。

image.png

为RenderArea小部件创建一个QPainter,并根据RenderArea的钢笔和笔刷设置画家的钢笔和笔刷。如果抗锯齿参数选项被选中,设置QPainter的渲染提示。

image.png

  • 渲染RenderArea的形状的多个副本。副本的数量取决于RenderArea小部件的大小,这里使用了两个for循环和小部件的高度和宽度来计算它们的位置。
  • 对于每个副本,首先保存当前的画家状态(将状态压入堆栈)。然后使用QPainter::translate()函数将坐标系统转换到由for循环变量决定的位置。如果省略了坐标系统的转换,所有形状的副本将会在RenderArea小部件的左上角相互叠加呈现。
  • 如果选中了transforms参数选项,那么在使用QPainter::rotate()函数将坐标系顺时针旋转60度并使用QPainter::scale()函数将其缩小之前,要将对坐标系进行额外的转换。最后,将坐标系平移回旋转和缩放之前的位置。
  • 当渲染这个形状时,它看起来就像在三维空间中旋转一样。

image.png

  • 确定RenderArea的形状,并使用相关的QPainter绘图功能渲染它。

image.png

  • 在开始渲染之前,保存了当前的绘制器状态(将状态压入堆栈)。这样做的基本原理是,计算每个形状副本相对于坐标系统中的同一点的位置。当转换坐标系时,除非在开始转换过程前保存当前的绘制状态,否则会失去这一点的知识。
  • 然后,完成渲染形状的副本时,可以使用QPainter::restore()函数,用它的相关坐标系统恢复原始的画家状态。通过这种方式,确保了下一个形状副本将被渲染在正确的位置。
  • 可以使用QPainter::translate()将坐标系统转换回来,而不是保存painter状态。但是,由于除了平移坐标系(当选中Transformation参数选项时)还旋转和缩放坐标系,最简单的解决方案是保存当前的画家状态。

一点感想:

在实现绘图时,一定要充分利用提供的一些现有的方法。