独立于规模 Canvas

Scale independent Canvas

我有一个可以缩放的 QML Canvas(更具体地说,它是一个缩放对象的子对象),缩放它会导致它的输出变得混叠。这是因为 Canvas 使用其大小来确定帧缓冲区大小。

我真正想要发生的是让帧缓冲区跟踪 Canvas 大小乘以它的比例,即它的屏幕像素大小。

我最初的想法是将 canvasWindowcanvasSize 设置为缩放后的大小,但是 Canvas 'pixel' 大小和 'pixel' 之间似乎没有解耦帧缓冲区的,因为整个图像开始渲染超出 Canvas.

的范围

在此示例中,黑色圆环在 Canvas 内呈现,该 Canvas 是缩放的灰色矩形的父级:

Canvas {
    id: borderCanvas
    anchors {
        fill: parent
        margins: 4
    }

    antialiasing: true
    canvasWindow: Qt.rect( 0,0,
                           width * parent.scale,
                           height * parent.scale );
    canvasSize: Qt.size( width * parent.scale,
                         height * parent.scale );

    onCanvasWindowChanged: {
        requestPaint();
    }

    onPaint: {
        var ctx = getContext( "2d" );
        ctx.save();
        ctx.clearRect( 0, 0, canvasWindow.width, canvasWindow.height );

        ctx.strokeStyle = Sy_application_qml.paletteObject.buttonText;
        ctx.lineWidth = 4 * parent.scale;

        ctx.beginPath();
        ctx.arc( canvasWindow.width / 2,
                 canvasWindow.height / 2,
                 ( canvasWindow.width / 2 ) - ctx.lineWidth,
                 0,
                 Math.PI * 2 );
        ctx.stroke();

        ctx.restore();
    }
}

那么,是否可以设置 Canvas 帧缓冲区大小,使缩放变换不影响它?

编辑

如果我将 canvasWindow 保留为默认值,并且只更新 canvasSize,那么我不会得到超出 Canvas 范围的帧缓冲区渲染 - 但输出仍在低分辨率,所以 canvasSize 仍然没有真正改变 帧缓冲区的大小...

解决方案是在 Canvas 上反转继承的缩放变换,然后按缩放量增加高度和宽度。这使 Canvas 在屏幕上保持相同大小,但具有匹配的帧缓冲区。

Canvas {
    id: borderCanvas
    anchors {
        top: parent.top
        left: parent.left
        margins: 4
    }

    property real viewScale: base.parent.scale

    scale: 1.0 / viewScale
    height: ( parent.height - ( anchors.margins * 2 ) ) * viewScale
    width:  ( parent.width  - ( anchors.margins * 2 ) ) * viewScale

    antialiasing: true
    transformOrigin: Item.TopLeft

    onPaint: {
        var ctx = getContext( "2d" );
        ctx.save();
        ctx.clearRect( 0, 0, width, height );

        ctx.strokeStyle = Sy_application_qml.paletteObject.buttonText;
        ctx.lineWidth = 4 * viewScale;

        ctx.beginPath();
        ctx.arc( width / 2,
                 height / 2,
                 ( width / 2 ) - ctx.lineWidth,
                 0,
                 Math.PI * 2 );
        ctx.stroke();

        ctx.restore();
    }
}