使用更新功能扩展 QML 图像类型

Posted

技术标签:

【中文标题】使用更新功能扩展 QML 图像类型【英文标题】:Extend QML Image type with an update function 【发布时间】:2016-12-15 10:40:43 【问题描述】:

正如大多数熟悉 QML 的人所知,QML Image 中没有内置的“刷新”功能。

我想创建一个新的 QML 类型,比如 RefreshableImage 来缓解这个问题,而不需要改变源代码,我觉得这是一个丑陋的 hack,因为它会渗透到模型-视图关系的所有层,而且切换行为是不自然的。此外,在Image 上设置不同的source 会破坏任何可能已设置的绑定(这实际上是问题的核心:我想要一个可更新的图像来保持其绑定,并且与 QML 隔离)。我知道我需要调用一些信号来实际刷新图像,这很好。

我很难找到有关扩展 Qt 自己的 Image 的文档,以便我可以强制它重新加载其源代码。我想避免编写一个完整的组件,该组件大多严重复制 Image 以添加一个功能。有没有办法像我想的那样扩展内置组件?

小笔记:

由于外部情况,我仅限于 Qt 5.5。 我们使用source 作为QQuickImageProvider 用来获取实际QImage 的底层图像对象的UUID。因此,我不想在更新图像时更改它。

【问题讨论】:

为什么你需要用相同的source 等更新Image?这不是同一张图吗? @folibis 技术上是的,但基础数据已经改变。我们使用 QML ImageProviders 从我们的数据结构中将 Qimage 提供给 QML。我们使用的 id 是我们系统中图像的 uuid,因此我们可以从该 uuid 检索其他地方的实际对象。为了简单起见,我们只是重用了这个 uuid。 嗯,好的,您应该在问题中指定这一点。我想这很重要。 也许你应该使用 UUID/version 而不仅仅是 UUID?我认为这是合乎逻辑的,因为 image => imageid 是一对一的链接。如果相同的 ID 涉及不同的图像/图像数据,那就不好了。顺便说一句,图像数据如何变化? 好吧。它与相同的(概念)图像有关,只是图像数据发生了变化。如果我可以为它编写一个组件,我真的很想避免添加版本绒毛...... 【参考方案1】:

您可以创建一个 RefreshableImage 类型来隐藏丑陋的源代码。

有一种简单的方法是为源引入一个新属性:

import QtQuick 2.0

Image 
    id: root
    property string refreshableSource
    source: refreshableSource
    function refresh() 
        source = "";
        source = Qt.binding(function()  return refreshableSource );
    

你必须这样使用它:RefreshableImage refreshableSource: "image.jpg"

如果您仍想使用source 作为属性,您可以使用一些别名恶作剧来实现。由于只有在组件完全初始化后才会激活别名,因此您可以覆盖 Imagesource 属性,但仍然可以访问底层。

import QtQuick 2.0

Image 
    id: root
    property alias actualUnderlyingSource: root.source //this refers to Image.source and not the newly created source alias
    property alias source: root.refreshableSource
    property string refreshableSource
    actualUnderlyingSource: refreshableSource
    function refresh() 
        actualUnderlyingSource = "";
        actualUnderlyingSource = Qt.binding(function()  return refreshableSource );
    

然后你可以像 RefreshableImage source: "image.jpg" 这样使用它,这实际上会修改 refreshableSource 属性

【讨论】:

有没有办法可以添加一些底层 C++ 来将其连接到实际的图像对象?如中,我可以用 C++ 扩展 QML 图像吗?我猜ImageRefresher C++/QML 组件/对象的组合会使这成为可能?我希望它能够收听/观察附加到相关 uuid 的对象。谢谢!【参考方案2】:

从带有自定义项的模型中直接使用 QImage 的粗略骨架

class DirectImage : public QQuickPaintedItem

    Q_OBJECT
    Q_PROPERTY(QImage image READ image WRITE setImage NOTIFY imageChanged)

public:
    void paint(QPainter *painer);
    void setImage(const QImage &image);
;

void DirectImage::paint(QPainter *painter)

    painter->drawImage(m_image.scaled(width(), height()):


void DirectImage::setImage(const QImage &image)

    m_image = image;
    emit imageChanged();
    setImplicitWidth(image.width());
    setImplicitHeight(image.height());
    update();

注册方式

qmlRegisterType<DirectImage>("MyElements", 1, 0, "RefreshableImage");

使用途径

import MyElements 1.0

// ...

RefreshableImage 
    image: model.image

当被要求提供图像角色时,模型只返回QImage,每当图像发生变化时,就会发出带有图像角色的dataChanged()信号。

如果需要按需生成图片,模型可以先返回空图片或者占位图片,当实际内容可用时发出dataChanged()信号。

【讨论】:

以上是关于使用更新功能扩展 QML 图像类型的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在 qml 中从网上下载图像

Swift之扩展的使用和实例展示

QML插件扩展

C#高级功能扩展方法和索引

Swift学习Swift编程之旅---扩展(二十四)

Python。设计。以相同的方式扩展各种功能