【问题标题】:QML How to paint different to grabToImage()QML如何绘制不同的grabToImage()
【发布时间】:2017-05-22 18:47:38
【问题描述】:

是否有任何可能的方法使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 有什么方法可以做到这一点吗?

【问题讨论】:

  • 您可以尝试创建第二个不可见的 ChartView 并使用 Timer 让 Qt 有时间处理所有内容,然后再将其保存为 PNG。
  • @m7913d ,这不是太直接的方式,但我会尝试 =)

标签: qt qml


【解决方案1】:

我不确定我是否完全正确。

我的建议是,不要抓取您显示的 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-property 来禁用它的更新。然后使用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!'
    }
}

【讨论】:

  • 这几乎正是 cmets 中的建议,但在我的情况下,这不是一个好的解决方案:由于性能原因,我不能同时更改两个图表系列(动态添加),因此我应该然后在用户想要拍摄快照时创建该图表的副本。无论如何,它需要将图表加倍 - 使用的内存加倍,这可能会成为一个巨大的瓶颈。
  • 您不会将数据翻倍。 ShaderEffectSource 仅复制视觉表示。你只有一个ChartView。也许我需要澄清我的答案来指出这一点。
  • 好吧,我开始明白了,这是一件有趣的事情。但是还有一个问题:我想用ChartView的方法来绘制图例。但我不知道如何禁用更新commonView,这样图例就不会出现在上面。当然,如果这根本不可能,我可以像使用 Text 一样切换到自己绘制传奇。
  • 这似乎有问题。我没有安装QtCharts,但似乎Legend 没有Item,因此可能不适合作为ShaderEffectSource 的来源。否则,您可以将其转为visible: false 并将我的Text 替换为另一个ShaderEffectSource 为源:chartView.legend,然后应该在保存的图像上再次可见。你可以试试(也许它是,虽然没有记录,并且是项目)——我不知道它是否会起作用。
  • 哇。我一定会尝试的。 Legend 只是布尔值,但可能里面有一些未记录的图例项
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-30
  • 1970-01-01
  • 2021-04-24
  • 2023-02-10
  • 2012-01-01
  • 2018-07-25
  • 1970-01-01
相关资源
最近更新 更多