【写在前面】
在qml中,要进行一般的绘图,如果不想使用C++ API,那么就只能使用Canvas了。
qml Canvas 提供HTML5 Canvas类似的API,需要修改HTML5 Canvas应用程序以在Canvas项中运行。
使用qml属性绑定或Canvas项方法替换所有DOM API调用。
使用MouseArea项替换所有HTML事件处理程序。
使用Timer项或使用requestAnimationFrame()更改setInterval / setTimeout函数调用。
将绘制代码放入onPaint处理程序并通过调用markDirty()或requestPaint()方法触发绘制。
要绘制图像,请通过调用Canvas的loadImage()方法加载它们,然后请求在onImageLoaded处理程序中绘制它们。
从Qt 5.4开始,Canvas是一个纹理提供者,可以直接在ShaderEffects和其他使用纹理提供者的类中使用。
注意:一般情况下,Canvas.Image渲染目标应避免使用大型画布,频繁更新和动画。这是因为使用加速图形API,每次更新都会导致纹理上传。
此外,如果可能的话,更应该使用QQuickPaintedItem并通过QPainter在C++中实现绘图,而不是更昂贵且可能性能更差的JavaScript和Context2D方法。
【正文开始】
首先,先上效果图:
其中,扫描部分的动画就是用Canvas做的,当然实际上要快很多。
接下来上代码:
import QtQuick 2.12
Item
{
id: root
clip: true
Canvas
{
id: canvas
anchors.fill: parent
antialiasing: true
property bool drawable: false;
property bool first: true;
property real r: Math.sqrt(Math.pow(width / 2, 2) + Math.pow(height / 2, 2));
property real r1: 0;
property real r2: r / 2;
function clear()
{
first = true;
r1 = 0;
r2 = r / 2;
var ctx = getContext("2d");
ctx.clearRect(0, 0, width, height);
}
function drawLine(ctx, color, width, startX, startY, endX, endY)
{
ctx.strokeStyle = color;
ctx.lineWidth = width;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.closePath();
ctx.stroke();
}
Timer
{
id: timer
interval: 16
running: false
repeat: true
onTriggered: canvas.requestPaint();
}
onPaint:
{
var ctx = getContext("2d");
ctx.fillStyle = "#10FFFFFF";
ctx.fillRect(0, 0, width, height);
for(var i = 0; i < width; i += 20)
drawLine(ctx, "#7266fc", 0.5,i + 0.5, 0, i + 0.5, height);
for(var j = 0; j < height; j += 20)
drawLine(ctx, "#7266fc", 0.5, 0, j + 0.5, width, j + 0.5);
if (drawable)
{
var halfW = width / 2;
var halfH = height / 2;
ctx.lineWidth = 2;
ctx.strokeStyle = "#72d6fc";
for(var k = 0; k < 5; k += 0.5)
{
ctx.beginPath();
ctx.arc(halfW, halfH, r1 + k, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
ctx.beginPath();
if(!first) ctx.arc(halfW, halfH, r2 + k, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
}
if(r1 > r) r1 = 0;
if(r2 > r)
{
r2 = 0;
if(first) first = false;
}
r1 += 3;
r2 += 3;
}
}
}
MyButton
{
text: "扫描"
widthMargin: 12
heightMargin: 8
anchors.centerIn: parent
onClicked:
{
canvas.clear();
canvas.drawable = true;
timer.restart();
discoverCon.discover();
}
}
}
onPaint是实际绘图的地方,但开始只会调用一次,因此需要使用Timer进行定时请求绘制,这里interva设置为16ms,即60fps,并且repeat为true(重复)。
Canvas中绘图步骤如下:
1、使用getContext()获取一个2D绘图上下文。
2、使用绘图上下文提供的API进行绘图。
步骤很简单,不过比较有意思的是其中的水波的半透明阴影效果的实现。
一般情况下,我们每一帧都需要清空上一帧绘制的内容,然鹅在这里,我们不清空,而是选择用一个接近透明的颜色来覆盖在上一帧绘制的内容之上,这里我用的颜色为#10FFFFFF(ARGB),这样,上一帧的内容就会成为半透明的效果,然后接着绘制本次帧(非透明),这样在视觉上,就会形成类似于半透明阴影的效果。
【结语】
emmm,其实本篇并没有多少值得写的东西,不过这个效果我从别的地方看到的,觉得有点意思,因此才想着写一篇来分析一下。
真正要写的是扫描和文件传输部分,这些后面我都会写的。