在QML中使用Canvas

本文介绍如何使用QML的Canvas组件实现扫描动画效果,包括动态纹理绘制、半透明阴影实现技巧及性能注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【写在前面】

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

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

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

<think>我们正在使用QML Canvas绘制矩形框。根据引用[4],Canvas本身不绘图,而是通过Context2D对象进行绘制。引用[3]提到Canvas仅提供了矩形的绘制API,但实际上我们可以通过Context2D的API绘制矩形。 绘制矩形的基本步骤: 1. 在QML中创建Canvas元素。 2. 在Canvas的onPaint事件中,获取Context2D对象。 3. 使用Context2D的API设置绘制样式(如颜色、线宽等)。 4. 调用绘制矩形的方法,如`context.rect(x, y, width, height)`,然后使用`context.stroke()`或`context.fill()`来绘制边框或填充。 示例代码: 下面是一个简单的示例,绘制一个红色边框的矩形,不填充。 */</think>### QML Canvas 绘制矩形框示例代码 在QML使用Canvas绘制矩形框主要通过`Context2D`对象实现,以下是具体示例代码: ```qml import QtQuick 2.15 Canvas { id: canvas width: 400 height: 300 // 绘制函数 onPaint: { // 获取2D绘图上下文[^4] var ctx = getContext("2d") // 清空画布 ctx.clearRect(0, 0, width, height) // 设置绘制样式 ctx.strokeStyle = "blue" // 边框颜色 ctx.lineWidth = 3 // 线宽 // 绘制矩形[^3][^4] ctx.beginPath() ctx.rect(50, 50, 200, 150) // (x, y, width, height) ctx.stroke() // 描边绘制 // 可选:绘制填充矩形 ctx.fillStyle = "#20FF0000" // 半透明红色填充 ctx.fillRect(100, 80, 180, 120) } // 组件加载完成后绘制 Component.onCompleted: { requestPaint() } } ``` #### 代码说明: 1. **基本矩形绘制**: - `ctx.rect(x, y, width, height)` 定义矩形路径 - `ctx.stroke()` 绘制边框 - `ctx.fillRect()` 直接绘制填充矩形(不包含边框) 2. **关键参数**: - `strokeStyle`:边框颜色(支持CSS颜色值) - `fillStyle`:填充颜色(支持透明度) - `lineWidth`:边框线宽(像素) 3. **绘制流程**: - 每次调用`requestPaint()`会触发`onPaint`信号 - `clearRect()`清空画布避免重叠 - 使用`beginPath()`开始新路径绘制 #### 高级用法: ```qml // 圆角矩形 ctx.beginPath() ctx.moveTo(50, 70) ctx.arcTo(50, 50, 70, 50, 10) // 左上角 ctx.arcTo(250, 50, 250, 70, 10) // 右上角 ctx.arcTo(250, 200, 230, 200, 10) // 右下角 ctx.arcTo(50, 200, 50, 180, 10) // 左下角 ctx.closePath() ctx.stroke() ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦起丶

您的鼓励和支持是我创作最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值