• QML Canvas 2D绘图<上>


      对比与qt的图形视图框架的介绍(可以查看我的其他博文https://www.cnblogs.com/laiyingpeng/p/12294990.html),本章介绍QML 2D绘图相关知识,本文提到的相关操作均指Qt Quick中,与HTML5以及JavaScript可能存在部分差异,均以本文为准。

    一、Canvas 介绍

      Qt Quick Canvas与HTML 5的canvas标签类似,基本使用方法包括绘制API、渐变、阴影、图像使用等,Canvas提供了一个空白绘图区域,可以利用api在上面绘制图形。

      Qt5引入了Canvas类型,该类型继承自Item,所以Canvas对象;也可以称为Canvas项目,Canvas提供了一个依赖分辨率的位图画布,能够使用JavaScript绘制直线和曲线、简单和复杂的图形、图像等等,还可以添加文本、颜色、渐变和图案以及像素的操作。

      Canvas项目API基于HTML5的canvas元素,其基本思想是提供一个用于渲染路径的Context2D对象,这个对象就是在Canvas上进行绘制的画笔,提供必要的绘图函数,包括画线、填充、渐变、文字、路径的创建等,更多细节类容可在帮助文档中搜索Canvas关键字了解:

    1.1 Canvas如何使用

      使用canvs对象创建一个宽100高200的绘制区域,代码如下:

    Canvas{
            id :canvas
             100
            height: 200
        }

    1.2 基本属性介绍

    available :该属性用于设置Canvs是否可用,只有为true时后续的操作才有效;

    canvasSize:设置canvas的逻辑大小,逻辑大小也是也是可以进行绘制的区域大小,默认情况下与当前画布中已有项目大小一致,虽然可以设置,但是只有出现在视口的元素时才会被Canvas渲染引擎绘制;

    renderStrategy:用于设置渲染策略

    renderTarget :用于设置canvas的渲染目标,目前支持以下两种

    二、绘制操作

      在QML中,Canvas扮演了绘制容器的角色,它本身不提供任何有关绘制的函数,所有的绘制操作都是通过getContext()函数获取Context2D上下文类型来完成,实际的绘制都是在Canvas的onPaint()事件处理器进行的

      Context2D提供了一个经典的二维笛卡尔坐标,默认情况下是与窗口坐标系统相同,原点(0,0)位于左上角,x轴正方向向右,y轴正方向向下,坐标如下:

       然而Canvas的坐标系并不是固定的,我们可以对坐标系统进行平移、缩放及旋转等,在后边的坐标转换一节我们会专门讲解。

    2.1 绘制参数设置

      Context2D类型提供了两种绘制方式:填充或描边

    • 填充会将一个区域的内部使用某种方式进行覆盖,使用fillStyle()函数
    • 描边则使用线条将一个区域的边框勾画出来,使用strokeStyle()函数

    2.2 绘制矩形

      Canvas没有提供过多的基本图元的绘制API仅有矩形的绘制,这是因为矩形相比其他图元更为常用,并且矩形的填充可以直接作为Canvas的背景填充,同时在实现动画等效果时,由于效率问题,通常还要清除某一矩形区域。

      针对矩形的绘制,Canvas提供了三种方法:

    • fillRect函数以填充方式绘制矩形;
    • strokeRect函数以描边方式绘制矩形
    • clearRect函数清除矩形区域

    示例如下:

    import QtQuick 2.12
    
    Canvas {
         200; height: 200
    
        onPaint: {
            var ctx = getContext("2d");
            ctx.fillStyle = "lightgrey" // 设置填充颜色为浅灰色
            ctx.strokeStyle = "blue" // 设置边线颜色为蓝色
            ctx.lineWidth = 4 // 设置边线宽度为4px
            ctx.lineJoin = "round"
    
            ctx.fillRect(20, 20, 160, 160)
            ctx.clearRect(30, 30, 140, 140)
            ctx.strokeRect(20, 20, 80, 80)
        }
    }

    运行效果如下:

    2.3 状态的保存与恢复

      Context2D是一个状态机,有很多状态,当前状态会一直保留,直到该状态被赋予新的值,但是如果我们绘制矩形a和b,绘制a时不指定指定颜色(默认黑色),绘制b时指定颜色绿色,程序运行后会出现黑色a和绿色b,但是当我们调整窗口大小后,会看到a和b都是绿色,这是因为绘制时上下文被填充成了绿色,当窗口大小改变后,画布内容需要重新绘制,由于Context2D是一个状态机,绘制第一个矩形时并没有指定填充颜色,,因而使用第二个矩形设置的绿色作为了填充色,这样两个矩形在绘制时都被绿色填充,那么如何修改呢,我们可以在每一个要绘制的前面都设置填充色,当然这可以解决,不过当绘制过程非常复杂需要设置很多属性时,一个个单独恢复之前的状态是不现实的,这里我们就要用到保存和恢复函数函数,如下介绍:

    • save()函数将当前属性值,压入状态栈;
    • restore()函数将save()函数压入状态栈的栈顶状态弹出恢复为上下文;

    下面看一个示例:

    import QtQuick 2.12
    
    Canvas {
       200; height: 100
    
      onPaint: {
        var ctx = getContext("2d")
        ctx.fillStyle = "black"
        ctx.fillRect(10, 10, 50, 50) // 第一个矩形
        ctx.save()
        ctx.fillStyle = ctx.createPattern("lightgrey", Qt.Dense1Pattern)
        ctx.fillRect(70, 10, 50, 50) // 第二个矩形
        ctx.restore()
        ctx.fillRect(130, 10, 50, 50) // 第三个矩形
      }
    }

    运行结果如下:

     我们使用restore恢复到save之前的状态。

    2.4 绘制文本

      与矩形类似,Canvas也提供了两种绘制文本的方法:

    • 填充:fillText(text,x,y)以填充方式绘制文本text,其中文本的左上角位于(x,y);
    • 描边:strokeText(text,x,y)以描边方式绘制文本text,其中文本的左上角位于(x,y);

    下面看一个示例:

    import QtQuick 2.12
    
    Canvas {
       210; height: 200
    
      onPaint: {
        var ctx = getContext("2d");
        ctx.fillStyle = "green"
        ctx.strokeStyle = "blue"
        ctx.lineWidth = 2
        ctx.font = "bold 50px Arial"
    
        var text = "qter.org";
        context.fillText(text, 10, 80)
        context.strokeText(text, 10, 150)
      }
    }

    运行结果如下:

    2.5 绘制路径

      Canvas提供了简单的矩形绘制API,但是实际应用中还有很多复杂图形,在Canvas中所有的图形都以路径为基础,我们以beginPath()和closePath()一组函数去通知Context2D开始绘制路径和结束绘制路径,一边形成一个环路,closePath也可有系统自动调用。

    • lineTo(x,y):该函数将提供当前坐标到x,y之间的一条直线;
    • object arc(real x, real y, real radius, real startAngle, real endAngle, bool anticlockwise):添加一段圆弧

     下面是一段示例:

    import QtQuick 2.12
    
    Canvas {
       240; height: 160
    
      onPaint: {
        var ctx = getContext("2d");
        ctx.lineWidth = 2
    
        ctx.beginPath()
        ctx.moveTo(0, 60)
        ctx.lineTo(240, 60)
        ctx.stroke()
    
        ctx.beginPath()
        ctx.moveTo(30, 60)
        ctx.arc(30, 60, 20, 0, -Math.PI / 2, true)
        ctx.stroke()
    
        ctx.beginPath()
        ctx.moveTo(90, 60)
        ctx.arc(90, 60, 20, 0, Math.PI, true)
        ctx.stroke()
    
        ctx.beginPath()
        ctx.moveTo(150, 60)
        ctx.arc(150, 60, 20, 0, -3 * Math.PI / 2, true)
        ctx.stroke()
    
        ctx.beginPath()
        ctx.moveTo(210, 60)
        ctx.arc(210, 60, 20, 0, Math.PI * 2, true)
        ctx.stroke()
      }
    }

    运行效果如下:

  • 相关阅读:
    卿学姐与魔法(优先队列)
    H国的身份证号码(搜索)
    钓鱼(贪心,优先队列)
    Communication System(动态规划)
    最长连续01字符串
    魔法跳舞链 (最小生成树)
    括号匹配(线段树)
    bzoj 1042: [HAOI2008]硬币购物
    bzoj 1057: [ZJOI2007]棋盘制作
    bzoj 1452: [JSOI2009]Count
  • 原文地址:https://www.cnblogs.com/laiyingpeng/p/12302566.html
Copyright © 2020-2023  润新知