QML如何绘制不同于grabToImage()

时间:2017-05-22 18:47:38

标签: qt qml

是否有任何可能的方法使grabToImage()缓冲区与GUI中显示的不同?我在GUI中使用没有图例的ChartView,并希望使用图例将其导出到PNG。所以我试试:

chartView.legend.visible = true
chartView.update()
chartView.grabToImage(function(result) {
    console.log("grabbed")

    var path = filename.toString().replace(/^(file:\/{2})/,"");
    console.log(path + result.saveToFile(path));
    chartView.legend.visible = false
    update();
});

但是这些更新只有在控件出来之后才会发生,因此我不会在PNG中绘制传奇。另外,我希望图例的外观对用户来说是不可察觉的。在QML中有没有办法做到这一点?

1 个答案:

答案 0 :(得分:3)

我不确定,我是否认为你是对的。

我的建议是,不要抓住你显示的Item,而是抓取它的副本,然后根据需要修改。
这里的复制并不意味着你有两次相同的对象,而是使用ShaderEffectSource渲染两次。在获取此ShaderEffectSource图像之前,您可以添加任何您喜欢的内容。

在我的示例中,我显示了一个带有漂亮渐变的简单Rectangle。我保存的内容与Rectangle'我是传奇'延长的Text相同。用户在任何时候都不会在视图中看到此文本。

Rectangle {
    id: commonView
    width: 200
    height: 200
    gradient: Gradient {
        GradientStop { position: 0; color: 'steelblue' }
        GradientStop { position: 1; color: 'orange' }
    }
    MouseArea {
        anchors.fill: parent

        // don't grab the rectangle itself.
        onClicked: legendView.grabToImage(function(result) {
            console.log(result.saveToFile("something.png"));
        });
    }
}

ShaderEffectSource {
    id: legendView
    visible: false // Does not need to be shown.
    sourceItem: commonView
    width: 200
    height: 200
    Text {
        anchors {
            right: parent.right
            bottom: parent.bottom
        }
        text: 'I am legend'
    }
}

您可以仅在ShaderEffectSource处于活动状态或甚至在需要时创建时优化性能。

您可以使用ShaderEffectSource.live - 属性来禁用它的更新。然后使用scheduleUpdate()触发更新。

这可能如下所示:

Rectangle {
    id: commonView
    width: 200
    height: 200
    gradient: Gradient {
        GradientStop { position: 0; color: 'steelblue' }
        GradientStop { id: gs1; position: 1; color: 'orange' }
    }
    MouseArea {
        anchors.fill: parent
        onClicked: {
            gs1.position -= 0.1
            legendView.save()
        }
    }
}

ShaderEffectSource {
    id: legendView
    y: 200
    visible: false // Do not render it (will only be rendered when called grapToImage()
    sourceItem: commonView
    width: 200
    height: 200
    live: false // Will only be updated, when explicitly called for
    function save() {
        console.log('Schedule Save')
        scheduleUpdate() // explicitly update. grabToImage() will force rendering afterwards.
        legendView.grabToImage(function(result) {
                        console.log(result.saveToFile("something" +gs1.position.toFixed(1) + ".png"));
                    })
    }

    // Put additional stuff on it.
    Text {
        anchors {
            right: parent.right
            bottom: parent.bottom
        }
        text: 'I am legend!'
    }
}