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()
  }
}

运行效果如下:

原文地址:https://www.cnblogs.com/laiyingpeng/p/12302566.html