前言
在QT4中加入QML时,一些开发者讨论如何在QtQuick中绘制一个圆形。类似圆形的问题,一些开发者也对于其它形状的支持进行了讨论。在QtQuick中没有圆形,只有矩形。在Qt4中,如果你需要一个除了矩形外的形状,你需要使用图片或者使用你自己写的C++的圆形元素。
Qt5中引入了Canvas元素,允许脚本绘制。Canvas元素提供了一个依赖于分辨率的位图画布,你可以使用JavaScript脚本来绘制图形,制作游戏或者其它的动态图像。Canvas元素是基于HTML5的画布元素来完成的。
Canvas元素的基本思想是使用一个2D对象来渲染路径。这个2D对象包括了必要的绘图函数,Canvas元素充当绘制画布。2D对象支持画笔,填充,渐变,文本和绘制路径创建命令。
简单的路径绘制示例
下面这个例子绘制了一个起点坐标为(50, 50),边长为100的填充矩形框,并且使用了画笔来修饰边界。
import QtQuick 2.3
import QtQuick.Window 2.2
Window {
id: root
visible: true
width: 480
height: 300
color: "white"
Canvas {
id: paint
width: 200
height: 200
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 4
ctx.strokeStyle = "blue"
ctx.fillStyle = "steelblue"
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
ctx.lineTo(150, 150)
ctx.lineTo(50, 150)
ctx.closePath()
ctx.fill()
ctx.stroke()
}
}
}
运行效果如下:
上面例子中,画笔的宽度被设置为4个像素,并且定义strokeStyle(画笔样式)为蓝色,填充样式(fillStyle)为steelblue。只有调用stroke或者fill函数,创建的路径才会绘制,它们与其它的函数使用是相互独立的。调用stroke或者fill将会绘制当前的路径,创建的路径是不可重用的,只有绘制状态能够被存储和恢复。
在QML中,Canvas元素充当了绘制的容器,2D绘制对象提供了实际绘制的方法。绘制需要在onPaint事件中完成,画布自身提供了典型的二维笛卡尔坐标系,左上角是(0, 0)坐标,Y轴坐标轴向下,X轴坐标轴向右。
典型绘制命令
典型的绘制命令调用如下:
- 装载画笔或者填充模式
- 创建绘制路径
- 使用画笔绘制填充绘制路径
以绘制最简单的直线为例:
Canvas {
id: paint
width: 200
height: 200
onPaint: {
var ctx = getContext("2d")
ctx.strokeStyle = "red"
ctx.beginPath()
ctx.moveTo(50, 50)
ctx.lineTo(150, 50)
ctx.stroke()
}
}
这将产生一个从(50, 50)到(150, 50)的水平线,运行效果如下:
通常在你重置了路径后你将会设置一个开始点,所以,在beginPath()这个操作后,你需要使用moveTo来设置开始点。
便捷的接口
在绘制矩形时,Qt提供了一个便捷的接口,而不需要调用stroke或者fill来完成。
Canvas {
id: paint
width: 200
height: 200
onPaint: {
var ctx = getContext("2d")
ctx.fillStyle = 'green'
ctx.strokeStyle = "blue"
ctx.lineWidth = 4
ctx.fillRect(20, 20, 180, 180)
ctx.clearRect(30, 30, 160, 160)
ctx.strokeRect(20, 20, 90, 90)
}
}
运行效果如下:
画笔的绘制区域由中间向两边延展。一个宽度为4像素的画笔将会在绘制路径的里面绘制2个像素,外面绘制2个像素。
渐变
画布中可以使用颜色填充也可以使用渐变色或者图像来填充。
下面的例子中,渐变色定义在开始点(100, 0)到结束点(100, 200)。在我们画布中时一个垂直线。渐变色在停止点定义一个颜色,范围从0.0到1.0。这里我们使用一个蓝色作为0.0(100, 0),一个高亮蓝色作为0。5(100, 200)。渐变色的定义比我们想要绘制的矩形更大,随意矩形在它定义的范围内对渐变进行了裁剪。
Canvas {
id: paint
width: 200
height: 200
onPaint: {
var ctx = getContext("2d")
var gradient = ctx.createLinearGradient(100, 0, 200, 200)
gradient.addColorStop(0, "blue")
gradient.addColorStop(0.5, "lightsteelblue")
ctx.fillStyle = gradient
ctx.fillRect(50, 50, 100, 100)
}
}
运行效果如下:
渐变色是在画布坐标下定义的,而不是在绘制路径相对坐标下定义的。画布中没有相对坐标的概念。