QML Canvas:渲染中的不同行为

Posted

技术标签:

【中文标题】QML Canvas:渲染中的不同行为【英文标题】:QML Canvas: different behaviour in rendering 【发布时间】:2016-02-25 13:31:39 【问题描述】:

我正在尝试使用 Canvas 对象在 QML 中绘制一个环形扇区。 首先,我已经编写了javascript代码,并通过在浏览器中执行它来验证它是正确的。

这里是:

var can = document.getElementById('myCanvas');
var ctx=can.getContext("2d");
var center = 
  x: can.width / 2,
  y: can.height / 2
;
var minRad = 100;
var maxRad = 250;

var startAngle = toRad(290);
var endAngle = toRad(310);

drawAxis();
drawSector();

function drawSector() 
  var p1 = 
    x: maxRad * Math.cos(startAngle),
    y: maxRad * Math.sin(startAngle)
  
  p1 = toCanvasSpace(p1);

  var p2 = 
    x: minRad * Math.cos(startAngle),
    y: minRad * Math.sin(startAngle)
  
  p2 = toCanvasSpace(p2);

  var p3 = 
    x: minRad * Math.cos(endAngle),
    y: minRad * Math.sin(endAngle)
  
  p3 = toCanvasSpace(p3);
  var p4 = 
    x: maxRad * Math.cos(endAngle),
    y: maxRad * Math.sin(endAngle)
  
  p4 = toCanvasSpace(p4);

  ctx.beginPath();
  ctx.moveTo(p1.x, p1.y);
  ctx.arc(center.x, center.y, maxRad, startAngle, endAngle);
  ctx.lineTo(p3.x, p3.y);
  ctx.arc(center.x, center.y, minRad, endAngle, startAngle, true);
  ctx.closePath();

  ctx.strokeStyle = "blue";
  ctx.lineWidth = 2;
  ctx.stroke();



function drawAxis() 
  ctx.beginPath();
  ctx.moveTo(can.width / 2, 0);
  ctx.lineTo(can.width / 2, can.height);
  ctx.stroke();
  ctx.beginPath();
  ctx.moveTo(0, can.height / 2);
  ctx.lineTo(can.width, can.height / 2);
  ctx.stroke();


function toRad(degrees) 
  return degrees * Math.PI / 180;


function toCanvasSpace(p) 
  var ret = ;
  ret.x = p.x + can.width / 2;
  ret.y = p.y + can.height / 2;
  return ret;

Here你可以运行上面的代码。 输出是这样的:

接下来,我将相同的代码移动到 Qml 中的 Canvas 对象中。

在这里查看包含 Canvas 的 main.qml:

import QtQuick 2.5
import QtQuick.Window 2.2

Window 
    visible: true
    width: 500
    height: 500
    x:500

    Canvas
    
        id: can
        anchors.fill: parent
        antialiasing: true



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

            var center = 
                x: can.width / 2,
                y: can.height / 2
            ;
            var minRad = 100;
            var maxRad = 250;

            var startAngle = toRad(290);
            var endAngle = toRad(310);

            drawAxis();
            drawSector();

            function drawSector() 
                var p1 = 
                    x: maxRad * Math.cos(startAngle),
                    y: maxRad * Math.sin(startAngle)
                
                p1=toCanvasSpace(p1);

                var p2 = 
                    x: minRad * Math.cos(startAngle),
                    y: minRad * Math.sin(startAngle)
                
                p2=toCanvasSpace(p2);

                var p3 = 
                    x: minRad * Math.cos(endAngle),
                    y: minRad * Math.sin(endAngle)
                
                p3=toCanvasSpace(p3);
                var p4 = 
                    x: maxRad * Math.cos(endAngle),
                    y: maxRad * Math.sin(endAngle)
                
                p4=toCanvasSpace(p4);

                ctx.beginPath();
                ctx.moveTo(p1.x, p1.y);
                ctx.arc(center.x, center.y, maxRad, startAngle, endAngle);
                ctx.lineTo(p3.x, p3.y);
                ctx.arc(center.x, center.y, minRad, endAngle, startAngle, true);
                ctx.closePath();

                ctx.strokeStyle="blue";
                ctx.lineWidth=2;
                ctx.stroke();
            


            function drawAxis() 
                ctx.beginPath();
                ctx.moveTo(can.width / 2, 0);
                ctx.lineTo(can.width / 2, can.height);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(0, can.height / 2);
                ctx.lineTo(can.width, can.height / 2);
                ctx.stroke();
            

            function toRad(degrees) 
                return degrees * Math.PI / 180;
            

            function toCanvasSpace(p) 
                var ret = ;
                ret.x = p.x + can.width / 2;
                ret.y = p.y + can.height / 2;
                return ret;
            


        
    

在这种情况下,我得到以下输出:

如您所见,底部有一个缺陷。

我真的不明白为什么会有这种缺陷;而且我不明白为什么相同的代码给出不同的输出。

感谢任何帮助! 谢谢

【问题讨论】:

【参考方案1】:

lineTo p3 是不需要的,因为在绘制arc 线段时,会根据Canvas 规范自动绘制连接线:

arc()方法等价于ellipse()方法 其中两个半径相等。 [...]

当调用 ellipse() 方法时,它必须进行如下操作。 首先,如果对象的路径有任何子路径,那么方法必须添加 从子路径中的最后一点到起点的直线 弧线。

另外,moveTo p1 也不需要,因为它会作为第一个弧的一部分完成。

至于为什么额外的线被画得比第二个弧的开始更远,这可能是 Qt 中的一个错误(可能是 0 的除法问题 - 只是在这里猜测),或者也许你根本没有计算它的位置正确。

【讨论】:

可以验证这是否修复了它。好的。 :) 哇,我确认这是一个解决方案!谢谢!

以上是关于QML Canvas:渲染中的不同行为的主要内容,如果未能解决你的问题,请参考以下文章

在没有 Canvas 的 QML 中绘制虚线圆

qml 中是不是可以重绘 Canvas 对象的内容?

在没有Canvas的QML中绘制虚线圆圈

UGUI初学习--------Canvas

QML Canvas.requestAnimationFrame 爆炸

Canvas和Svg有啥区别?