在QML中使用Canvas

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011283226/article/details/89355467

【写在前面】

在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方法。


【正文开始】

首先,先上效果图:

扫描二维码关注公众号,回复: 5974100 查看本文章

其中,扫描部分的动画就是用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,其实本篇并没有多少值得写的东西,不过这个效果我从别的地方看到的,觉得有点意思,因此才想着写一篇来分析一下。

真正要写的是扫描和文件传输部分,这些后面我都会写的。

最后,项目地址:https://github.com/mengps/FileTransfer

猜你喜欢

转载自blog.csdn.net/u011283226/article/details/89355467