Qt Quick之Canvas

QML中的Canvas,俗称画布,它用来定义一个绘图区域,可以使用ECMAScript代码来绘制直线,矩形,贝塞尔曲线,弧线,图片,文字等图元,还可以为这些图元应用填充颜色和边框颜色,甚至还可以进行低

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

  QML中的Canvas,俗称画布,它用来定义一个绘图区域,可以使用ECMAScript代码来绘制直线,矩形,贝塞尔曲线,弧线,图片,文字等图元,还可以为这些图元应用填充颜色和边框颜色,甚至还可以进行低阶的像素级的操作。

1. 几个重要概念

(1)画布

  下面的代码定义了一个宽320像素高240像素的画布

Canvas
{
    width:320;
    height:240;
}

(2)画师

  画师如同MFC中的DC和Qt C++中的QPainter,那么QML中的画师是谁呢?Content2D是也!可以在Qt帮助文档中使用索引模式查找“Context2D”关键字来查看相关信息。

  方法1: 

Canvas
{
    onPaint:    
    {
        var ctx = getContext("2d");
    }
}

  方法2:

Canvas{
    id:canvas;
    contextType:"2d";

    onPaint:{
        context.lineWidth=2;
    }
}

(3)画笔

  lineWidth:设置画笔的宽度

  strokeStyle:设置画笔颜色或风格

(4)画刷

  在context2D这里,fillStyle属性是描述画刷的

(5)坐标系

  (0,0)为左上角,x轴水平向右为正,y轴垂直向下为正

(6)图元

  基本图元有线,弧,矩形,曲线,文本,图片等

2. 基本绘图模式

 Canvas
    {
        width:400;
        height:240;
        onPaint:
        {
            var ctx = getContext("2d");

            ctx.lineWidth = 2;  // 设置画笔宽度
            ctx.strockStyle="red"; // 设置画笔颜色
            ctx.fillStyle="blue"; // 设置填充色

            ctx.beginPath();
            ctx.rect(100,80,120,80);
            ctx.fill();
            ctx.stroke();
        }
    }

  上面代码演示如何绘制一个矩形和矩形边框,展示了使用Canvas和Context2D绘图的一般步骤:

(1)定义一个Canvas对象,设置width和Height

(2)定义onPaint信号处理器

(3)获取Context2D对象

(4)实际的绘图操作

3. 绘制路径

  使用Content2D绘制路径的一般步骤:

(1)调用beginPath()

(2)调用moveTo(),lineTo(),rect(),quadraticCurveTo(),arc(),bezierCurveTo()等可以构造路径元素的方法

(3)调用fill()或stroke()

  这里主要介绍下fillStyle属性的使用,fillStyle与Qt C++中的QBrush类似,保存用于填充图元的画刷,它可以是一个颜色值,也可以是CanvasGradient或CanvasPattern对象

Canvas
    {
        width: 400;
        height: 240;
        contextType:"2d";
        onPaint:
        {
            var ctx = getContext("2d");
            ctx.lineWidth = 2;
            ctx.lineJoin = "round"
            ctx.strokeStyle = "red";
            ctx.font = "42px sans-serif";

            //ctx.fillStyle = "blue"; // 使用颜色进行填充
            var gradient = ctx.createLinearGradient(100,80,220,160);
            gradient.addColorStop(0, Qt.rgba(255,255,255,1));
            gradient.addColorStop(1, Qt.rgba(0,0,0,1));
            ctx.fillStyle =gradient; // 使用渐变对象进行填充

            ctx.beginPath();
            ctx.moveTo(240,80);
            ctx.lineTo(300,90);
            ctx.rect(100,80,250,150);
            ctx.text("stroke text", 110,120);
            ctx.fill();

            ctx.stroke();
        }
    }

  注意:closePath()方法用于结束当前的路径,从路径终点到起点绘制一条直线来封闭路径,比如:

ctx.beginPath();
ctx.moveTo(100,80);
ctx.lineTo(100,200);
ctx.lineTo(300,200);
ctx.closePath();
ctx.fill();
ctx.stroke();

  通过closePath绘制一个三角形

4. 绘制文本

Context2D对象与文本相关的方法有三个:fillText(),strokeText(),text()

fillText()使用fillStyle填充文字

strokeTexr()使用strokeStyle描文字边框

text()方法在路径上添加一串文本作为构成路径的元素之一

上面代码效果:

Qt Quick之Canvas

5. 绘制图片

  Context2D有4种不同形式的drawImage()方法,可以用来绘制图片

(1)显示本地图片

(2)显示网络图片

Canvas
    {
        width: 600;
        height: 600;
        id:canvas;
        property var imageName: "dartlike_weapon.png";
        property var imageUrl: "http://g2.ykimg.com/0516000053548ED267379F510C0061FA";

        onPaint:
        {
            var ctx = getContext("2d");

            ctx.drawImage(imageUrl, 200,0); // 绘制网络图片

            ctx.drawImage(imageName, 0,200);   // 绘制本地图片
        }

        Component.onCompleted:
        {
            loadImage(imageUrl);  // 异步加载图片,图片加载完发射imageLoaded信号
            loadImage(imageName);
        }

        onImageLoaded:
        {
            requestPaint();  // 重绘Canvas
        }
    }

  上面的代码演示了显示本地和网络图片,Component.onCompleted附加信号处理器内调用Canvas的loadImage()方法来加载图片,该方法会异步加载图片,当图片加载完成时,发射imageLoaded信号,在对应的信号处理器onImageLoaded内调用requestPainte()方法来重回Canvas.怎样知道图片是否加载成功了呢?可以通过Canvas的isImageError(),isImageLoaded()两个方法来判断,他们接受和loadImage()同样的参数,返回布尔值,只有成功加载的图片才可以使用Context2D来绘制。

(3)使用Image属性显示网络图片

    Image
        {
            id:imageSource;
            source: "http://g2.ykimg.com/0516000053548ED267379F510C0061FA";
            visible: false;
            onStateChanged: {
                if(status == Image.Ready)
                {
                    canvas.requestPaint();
                }
            }
        }

(4)使用createImageData显示图像

  drawImage还可以绘制CanvasImageData对象,CanvasImageData对象使用一维数组,按照RGBA的顺序来保存图像数据

    onPaint:
        {
            var ctx = getContext("2d");

            if(imageData == null)
            {
                imageData = ctx.createImageData(120,100);
                for (var i = 0;i < 48000;i+=4)
                {
                    imageData.data[i] = Math.floor(Math.random()*255);
                    imageData.data[i+1] = Math.floor(Math.random()*255);
                    imageData.data[i+2] = Math.floor(Math.random()*255);
                    imageData.data[i+3] = 255;
                }
            }

            ctx.drawImage(imageData,0,0);   // 绘制createImageData
        }

(5)4种方法的综合实例

Qt Quick之Canvas
Qt Quick之Canvas

import QtQuick 2.9
import QtQuick.Window 2.2

Window {
    visible: true
    width: 800
    height: 600
    title: qsTr("Hello World")

    Canvas
    {
        width: 600;
        height: 600;
        id:canvas;
        property var imageName: "dartlike_weapon.png";
        property var imageUrl: "http://g2.ykimg.com/0516000053548ED267379F510C0061FA";

        Image
        {
            id:imageSource;
            source: "http://g2.ykimg.com/0516000053548ED267379F510C0061FA";
            visible: false;
            /*onStateChanged: {
                if(status == Image.Ready)
                {
                    canvas.requestPaint();
                }
            }*/
        }

        property var imageData: null;
        onPaint:
        {
            var ctx = getContext("2d");

            if(imageData == null)
            {
                imageData = ctx.createImageData(120,100);
                for (var i = 0;i < 48000;i+=4)
                {
                    imageData.data[i] = Math.floor(Math.random()*255);
                    imageData.data[i+1] = Math.floor(Math.random()*255);
                    imageData.data[i+2] = Math.floor(Math.random()*255);
                    imageData.data[i+3] = 255;
                }
            }

            ctx.drawImage(imageData,0,0);   // 绘制createImageData
            ctx.drawImage(imageUrl, 200,0); // 绘制网络图片

            ctx.drawImage(imageSource, 200,200); // 绘制image属性
            ctx.drawImage(imageName, 0,200);   // 绘制本地图片
        }

        Component.onCompleted:
        {
            loadImage(imageUrl);  // 异步加载图片,图片加载完发射imageLoaded信号
            loadImage(imageName);
            loadImage(imageSource);
        }

        onImageLoaded:
        {
            requestPaint();  // 重绘Canvas
        }
    }
}

View Code

Qt Quick之Canvas

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120076.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • stm32基础知识必会_护理学基础必考知识点

    stm32基础知识必会_护理学基础必考知识点目录【GPIO外设】一、GPIO的八种工作模式二、总结在STM32中选用IO模式【RCC时钟】【NVIC是嵌套向量中断控制器】一、优先级定义二、优先级分组【EXTI外部中断/事件控制器】【SysTick系统定时器】【通讯的基本概念】一、串行通讯与并行通讯二、全双工、半双工及单工通讯三、同步通讯与异步通讯四、通讯速率【串口通讯】一、物理层:二、协议层【I2C】一、物理层二、协议层【SPI】一、SPI物理层二、协议…

    2022年9月6日
    5
  • laravel 5.4 导出excel表格

    laravel 5.4 导出excel表格

    2021年10月24日
    43
  • 什么是公网IP和内网IP?NAT转换又是什么鬼?[通俗易懂]

    什么是公网IP和内网IP?NAT转换又是什么鬼?[通俗易懂]https://www.jianshu.com/p/4cd76e25b8941、引言搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢?另外,内行都知道,提到外网IP和内网IP就不得不提NAT路由转换这种东西,那这双是什么鬼?本文就来简单讲讲这些到底都是怎么回事。1、每台电脑都必须要一个公网IP吗?答案:不是。我们都知道,IPv4中的IP地址的数量是有限的(所以现在都在搞IPv6嘛),每..

    2022年5月29日
    36
  • 什么是守护线程?「建议收藏」

    什么是守护线程?「建议收藏」Java线程分为用户线程和守护线程。守护线程是程序运行的时候在后台提供一种通用服务的线程。所有用户线程停止,进程会停掉所有守护线程,退出程序。Java中把线程设置为守护线程的方法:在start线程之前调用线程的setDaemon(true)方法。注意:setDaemon(true)必须在start()之前设置,否则会抛出IllegalThreadStateExc…

    2022年10月15日
    1
  • 镁光闪存颗粒对照表_详解闪存颗粒的种类

    镁光闪存颗粒对照表_详解闪存颗粒的种类固态硬盘的存储颗粒从目前来看主要分为SLC,MLC,TLC,QLC.这四种存储颗粒的区别主要体现在那方面,以下我们就从价格,使用寿命,应用场合来划分.SLCMLCTLCQLC示意图SLC:单层次存储单元SLC=Single-LevelCell,即1bit/cell,速度快寿命最长,价格贵(约MLC3倍以上的价格),约10万次擦写寿命.是目前使用寿命最高的颗粒,由于价格贵,产能少,…

    2022年6月22日
    100
  • A记录、CNAME和URL转发区别[通俗易懂]

    A记录、CNAME和URL转发区别[通俗易懂]我们在做域名解析时,尤其是很多虚拟主机,大都会使用到CNAME解析,独立主机、VPS则用A记录较多,而URL转发则会在更换域名时用到,从设置效果来看,都是“解析”到一个“其它”URL地址,而实际上它们之间还是有些区别的,尤其是URL转发和其它两个之间区别很大的,首先A记录和CNAME属于标准的DNS记录,而URL转发则实际上只是个简单的重定向。另外,我们还常遇到别名ALIAS这个词,ALIAS对解

    2022年10月9日
    3

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号