3
votes

As most people familiar with QML know, there is no builtin "refresh" functionality in QML Image.

I would like to create a new QML type, say RefreshableImage to alleviate this problem without resorting to changing the source, which I feel is an ugly hack, as it bleeds into all layers of the Model-View relationship and this switching behaviour is unnatural. Additionally, setting a different source on an Image breaks any binding that may have been set (which is really the core of the problem: I want an updateable image that maintains its binding, and is isolated to QML). I understand I'll need to call some signal to actually refresh the image, that's fine.

I have trouble finding documentation on a way to extend Qt's own Image so that I can force it to reload its source. I would like to avoid writing a complete component that mostly badly replicates Image to add one function. Is there a way to extend a builtin component like I have in mind?

Minor notes:

  • due to external circumstances, I'm limited to Qt 5.5.
  • We use as source a UUID of the underlying image object which is used by an QQuickImageProvider to get the actual QImage. Hence I don't want to change this when updating an image.
2
Why you need to update Image with same source etc.? Isn't that the same image?folibis
@folibis technically yes, but the underlying data has changed. We use QML ImageProviders to supply the Qimages to QML from our data structures. The id we use is the uuid of the image in our system, so we can retrieve the actual object elsewhere from that uuid. We're just reusing this uuid for simplicity's sake.rubenvb
Ah ok, you should to specify this in the question. I guess that's important.folibis
May be you should use UUID/version instead of just UUID? I think that would've been logical since image => imageid is a one to one link. It's not good if same ID relates to different image / image data. Btw, how the image data changes?folibis
Well. It relates to the same (conceptual) image, it's just that the image data has changed. I really want to avoid adding version fluff all over if I can write a component for it...rubenvb

2 Answers

3
votes

You could create a RefreshableImage type that hides the ugly source changing from you.

There's a simple way of doing it by introducing a new property for the source :

import QtQuick 2.0

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

You have to use it like that : RefreshableImage { refreshableSource: "image.jpg" }.

If you want to still use source as a property, you could do it with some aliases shenanigans. Since aliases are only activated once a component has been fully initialized, you can overwrite the source property of Image but still be able to access the underlying one.

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 });
    }
}

You could then use it like so RefreshableImage { source: "image.jpg" }, this will in fact modify the refreshableSource property

0
votes

A rough skeleton for directly using QImage from a model with a custom item

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();
}

Registered via

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

Use via

import MyElements 1.0

// ...

RefreshableImage {
    image: model.image
}

The model just returns the QImage when asked for the image role, emits the dataChanged() signal with the image role whenever the image changes.

If the image needs to be generated on demand, the model can first return an empty image or a placeholder image and emit the dataChanged() signal when the actual content is available.