7.画布(Canvas)元素
** 注意: **
最新的构建时间:2016/03/21
这章的源代码能够在assetts folder找到。
早在 Qt 4 引入 QML 时,是有一些关于 Qt Quick 需要一个椭圆的讨论的。如果要加入椭圆的话,那么是不是其他人可以提出加入其他的形状,那么是不是也需要支持呢?所以在 Qt Quick 中并没有椭圆形只有矩形。如果我们在 Qt 4 中需要的话,则需要使用图片或者编写自己的 C++ 椭圆元素。
为了支持脚本绘图 Qt 5 引入了 Canvas 元素。画布元素提供了一个依赖于分辨率的位图画布,可用于图形,游戏或使用 JavaScript 即时绘制其他可视图像。Canvas 元素基于 HTML5 的 Canvas 元素。
canvas 元素的基本思想是使用上下文 2D 对象来渲染路径。 上下文 2D 对象包含必要的图形功能,而画布则作为绘图画布。2D 上下文支持笔画,填充,渐变,文本和不同的路径创建命令集。
我们来看一个简单的路径图的例子:
import QtQuick 2.5
Canvas {
id: root
// canvas size
width: 200; height: 200
// handler to override for drawing
onPaint: {
// get context to draw with
var ctx = getContext("2d")
// setup the stroke
ctx.lineWidth = 4
ctx.strokeStyle = "blue"
// setup the fill
ctx.fillStyle = "steelblue"
// begin a new path to draw
ctx.beginPath()
// top-left start point
ctx.moveTo(50,50)
// upper line
ctx.lineTo(150,50)
// right line
ctx.lineTo(150,150)
// bottom line
ctx.lineTo(50,150)
// left line through path closing
ctx.closePath()
// fill using fill style
ctx.fill()
// stroke using line width and stroke style
ctx.stroke()
}
}
这产生一个填充的矩形,起始点为 50,50,大小为 100,笔画用作边框装饰。
笔画宽度设置为 4,并使用由 strokeStyle 定义的蓝色。最终的形状被设置为通过 fillStyle 填充的“steelblue” 颜色。只有通过调用 stroke 或 fill 实际路径才能绘制出来,可以独立使用。调用 stroke 或 fill 将绘制当前路径。不能存储路径以供稍后重用,绘制状态只能存储(stored)和还原(restored)。
在 QML 中,Canvas 元素充当绘图的容器。 2D 上下文对象提供实际绘图操作。实际绘图需要在 onPaint 事件处理程序中完成。
Canvas {
width: 200; height: 200
onPaint: {
var ctx = getContext("2d")
// setup your path
// fill or/and stroke
}
}
画布本身提供了典型的二维笛卡尔坐标系,其中左上角是(0,0)点。y 值随着向下增加而增加,x 值随着向右移动增加。
基于路径的 API 的典型命令顺序如下:
- 设置笔触、填充或笔触和填充同时设置
- 创建路径
- 设置笔触、填充或笔触和填充同时设置
onPaint: {
var ctx = getContext("2d")
// setup the stroke
ctx.strokeStyle = "red"
// create a path
ctx.beginPath()
ctx.moveTo(50,50)
ctx.lineTo(150,50)
// stroke path
ctx.stroke()
}
这产生从点 P1(50,50) 到点 P2(150,50) 的水平划线。
** 注意: **
通常,我们总是希望在重置路径时设置一个起点,因此在 beginPath 之后的第一个操作通常是 moveTo。
7.1 便捷的 API
对于矩形操作,提供方便的API,直接调用笔触或填充进行绘制。
// convenient.qml
import QtQuick 2.5
Canvas {
id: root
width: 120; height: 120
onPaint: {
var ctx = getContext("2d")
ctx.fillStyle = 'green'
ctx.strokeStyle = "blue"
ctx.lineWidth = 4
// draw a filles rectangle
ctx.fillRect(20, 20, 80, 80)
// cut our an inner rectangle
ctx.clearRect(30,30, 60, 60)
// stroke a border from top-left to
// inner center of the larger rectangle
ctx.strokeRect(20,20, 40, 40)
}
}
** 注意: **
行程区域延伸各占路径两侧线宽的一半。4 px lineWidth 将在路径外面绘制 2 像素,内部 2 像素。
7.2 渐变
画布可以使用颜色的形状填充,但也可以使用渐变或图片。
onPaint: {
var ctx = getContext("2d")
var gradient = ctx.createLinearGradient(100,0,100,200)
gradient.addColorStop(0, "blue")
gradient.addColorStop(0.5, "lightsteelblue")
ctx.fillStyle = gradient
ctx.fillRect(50,50,100,100)
}
该示例中的渐变沿着起始点(100,0)到终点(100,200)定义,这在画布的中间给出了一条垂直线。 梯度停止可以定义为从0.0(渐变起始点)到1.0(渐变终点)的颜色。 这里我们在位置 0.0(100,0) 使用颜色“blue”,在位置 0.5(100,200) 使用颜色“lightsteelblue”。渐变的范围比我们要绘制的矩形大得多,因此矩形将渐变剪切和限定在其形状范围内。
** 注意: **
渐变要在画布坐标中定义,而不是相对于要绘制的路径的坐标。画布没有相对坐标的概念,就像现在我们在 QML 中使用的那样。
7.3 阴影
可以使用 2D 上下文对象的阴影来增强路径的显示效果。阴影是路径周围的区域,具有偏移,颜色和指定的模糊。为此,我们可以指定一个 shadowColor、shadowOffsetX、shadowOffsetY 和 shadowBlur。 所有这一切都需要使用 2D 上下文来定义。 2D 上下文是我们唯一的绘图操作 API。
也可以使用阴影在路径周围创建辉光效果。在下一个例子中,我们创建一个文字“Canvas”,周围有白色的光晕。 所有这一切都在黑暗的背景下,以提高可见度。
首先我们画出黑暗的背景:
// setup a dark background
ctx.strokeStyle = "#333"
ctx.fillRect(0,0,canvas.width,canvas.height);
然后,我们定义我们的阴影配置,它将用于下一个路径的显示:
// setup a blue shadow
ctx.shadowColor = "#2ed5fa";
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 10;
最后,我们使用 Ubuntu 字体系列中的一个大胆的 80px 大小的字体绘制 “Canvas” 文本。
// render green text
ctx.font = 'bold 80px Ubuntu';
ctx.fillStyle = "#24d12e";
ctx.fillText("Canvas!",30,180);
下面是其显示效果: