Qt Quick之Canvas


  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()方法在路徑上添加一串文本作為構成路徑的元素之一

上面代碼效果:

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種方法的綜合實例

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM