Content Table

画刷

画刷 QBrush 是用来填充图形用的

The QBrush class defines the fill pattern of shapes drawn by QPainter.
A brush has a style, a color, a gradient and a texture.

下图在来自 QBrush 的帮助文档内容,列出了 Qt 自带的 brush:

画刷还可以使用 QPixmap,渐变等来创建。

平铺绘制 QPixmap 可以使用 QPainter::drawTiledPixmap(),也可以像下面这样使用 texture pattern 实现平铺绘制:

1
2
3
4
5
6
7
8
9
void MainWidget::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);

QPixmap pixmap(":/resources/Paint-Base-Bufferfly.png");
QBrush brush(pixmap);
painter.setBrush(brush);
painter.drawRect(0, 0, width(), height());
}

蚂蚁线

蚂蚁线是一个典型的 QPen 自定义 style 的应用,这里将介绍怎么使用 Qt 实现蚂蚁线。

QPen 已经提供了一些默认的 style,如 SolidLine, DashLine 等,但是满足不了所有的需求,所以还提供了自定义 style 的接口 QPen::setDashPattern(),其参数是一个 QVector,vector 中下标为偶数的位置存储 dash 的长度,奇数位置存储空白的长度,如 vector 的数据为 [3, 4, 9, 4](偶数个元素)表示:画线时以 3 个 dash 开始,接着是4 个空白,接下来是 9 个 dash,4 个空白,此时 vector 的元素已经用完,则从头开始使用 vector 的元素,接着画 3 个 dash,4 个空白,9 个 dash,4 个空白,依此类推。

画笔

画笔 QPen 用来绘制轮廓,和画笔相关也有很多概念,要理解好画笔也需要下很多工夫的,先看个简单的例子,直观的理解一下什么是 Cap Style, Join Style, Pattern 等上图。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void MainWidget::paintEvent(QPaintEvent *) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.translate(50, 50);

QPainterPath path;
path.lineTo(100, 100);
path.quadTo(200, 100, 200, 0);

QPen pen1(Qt::darkGray, 20, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
painter.setPen(pen1);
painter.drawPath(path);
painter.drawRect(250, 0, 200, 100);

// 自定义 dash pattern
QPen pen2;
QVector<qreal> dashes;
qreal space = 4;
dashes << 3 << space << 9 << space << 27 << space;
pen2.setDashPattern(dashes);

painter.translate(-30, -30);
painter.setPen(pen2);
painter.drawRect(0, 0, 510, 160);
}

贝塞尔曲线

QPainterPath 可以用来画贝塞尔曲线,什么是贝塞尔曲线呢?开始学的时候,经常听到贝塞尔曲线,但一直不知道是什么东西,很神秘的样子,据说很复杂,一直没敢学,人类对陌生的东西总是有恐惧感,这一部分就来揭开贝塞尔曲线神秘的面纱(大部分内容都来自于网络)。

贝塞尔曲线(The Bézier Curves),是一种在计算机图形学中相当重要的参数曲线(3D的称为曲面)。贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所发表,他运用贝塞尔曲线来为汽车的主体进行设计。

一般的矢量图形软件通过它来精确画出曲线,贝塞尔曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。

绘制路径

路径 QPainterPath,先引用一段 Qt 帮助文档里对路径的描述吧:

A painter path is an object composed of a number of graphical building blocks, such as rectangles, ellipses, lines, and curves. Building blocks can be joined in closed subpaths, for example as a rectangle or an ellipse. A closed path has coinciding start and end points. Or they can exist independently as unclosed subpaths, such as lines and curves.

A QPainterPath object can be used for filling, outlining, and clipping.

也就是说,路径可以由多个图形组成,例如矩形、椭圆、线、曲线、贝塞尔曲线等,一个路径可以和另一个路径合并,也可以从一个路径里扣掉另一个路径,路径可以用来创建复杂的图形,也可以用来限制绘图的区域实现特殊的效果等。

绘图基础

这一节介绍 Qt 的绘图基础知识,我们都知道,Qt 里绘图使用的是 QPainter,但是首先需要弄明白:在什么上绘图和在哪里绘图,然后才是怎么绘图,我们就围绕这几个问题来展开。

在什么上绘图

The QPaintDevice class is the base class of objects that can be painted on with QPainter.

A paint device is an abstraction of a two-dimensional space that can be drawn on using a QPainter. Its default coordinate system has its origin located at the top-left position. X increases to the right and Y increases downwards. The unit is one pixel.

The drawing capabilities of QPaintDevice are currently implemented by the QWidget, QImage, QPixmap, QGLPixelBuffer, QPicture, and QPrinter subclasses.

上面的内容来自于 Qt 的帮助文档,在 QPaintDevice 的子类里用 QPainter 绘图,最常见的就是在 QWidget, QPixmap, QPixture, QPrinter 上面绘图。

绘图

阿基米德说:给我一个支点,我将撬起整个地球。给我一个 QPainter,我也能实现整个操作系统的图形界面,看似有点夸张,但说明了一个核心问题,操作系统的界面本质也是画(Hua)出来的。你看到的,未必就是真实存在的,也可以说根本不存在什么按钮、Label 等,他们都是一幅画,有很多人认为按钮就是按钮,Label 就是 Label,是不同的控件,不能互相转换使用,其实我很多时候就会把按钮当 Label 用,例如要求显示左边是图标,右边是文字,不可点击,如果用 Label 来实现就比较麻烦,但用 QPushButton 来做的话很容易,只不过把点击事件给忽略就好,处理 Label 的鼠标点击事件是不是就可化身为按钮了呢?别说按钮等了,其实就是我们生存的空间,都不知道是否真实的存在,还是我们就生活在外星文明的游戏里,谁能说得清呢!