Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[Solved] Asynchronous QQuickImageProvider with a timeout



  • Hi,

    I can't seem to figure out how to set a timer with an asynchronous ImageProvider. The first thing I tried was

    @
    QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
    {
    QTimer::singleShot(100,this,SLOT(myTimeout()));
    ...
    doImageProviderThings();
    ...
    return image;
    }
    @

    where myTimeout() is a slot with some implementation in MyImageProvider. Unfortunately QTimer was not able to interrupt the thread and myTimeout() executed when requestImage() returned.

    Next I tried making QTimer* m_timer a member of MyImageProvider and connecting it to some signals in the MyImageProvider constructor:

    @
    MyImageProvider::MyImageProvider(QQuickImageProvider::ImageType type) :
    QObject(0),
    QQuickImageProvider(type, QQuickImageProvider::ForceAsynchronousImageLoading)
    {
    m_timer = new QTimer(this);
    m_timer->setInterval(100);
    m_timer->setSingleShot(true);
    connect(m_timer,SIGNAL(timeout()),this,SLOT(myTimeout()));
    connect(this, SIGNAL(finished()),m_timer,SLOT(stop()));
    connect(this, SIGNAL(started()), m_timer, SLOT(start()));
    }

    QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
    {
    emit started();
    ...
    doImageProviderThings();
    ...
    emit finished();
    return image;
    }
    @

    but as far as I can tell m_timer is never even started (the signals connected in the constructor are never detected).

    Lastly, I tried setting up the connections in requestImage, but the program crashed when it got the the connect() statement:
    @
    MyImageProvider::FilmImageProvider(QQuickImageProvider::ImageType type) :
    QObject(0),
    QQuickImageProvider(type, QQuickImageProvider::ForceAsynchronousImageLoading)
    {
    m_timer = new QTimer(this);
    m_timer->setInterval(100);
    m_timer->setSingleShot(true);
    }

    QImage MyImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
    {
    connect(m_timer,SIGNAL(timeout()),this,SLOT(myTimeout()));
    connect(this, SIGNAL(finished()),m_timer,SLOT(stop()));
    connect(this, SIGNAL(started()), m_timer, SLOT(start()));
    emit started();
    ...
    doImageProviderThings();
    ...
    emit finished();
    return image;
    }
    @

    I'm out of ideas. Any help would be greatly appreciated!



  • For your first attempt: You might have to check for events, either by calling qApp->processEvents(); in doImageProviderThings or by starting an event loop. (http://qt-project.org/doc/qt-5.0/qtcore/timers.html)



  • Okay thanks! But you think you could expand on how I could start an event loop? My confusion lies in the fact that I am already on a separate thread of execution and I'm able to send and receive signals to/from QML.



  • It depends on how you doImageProviderThings function looks. If there's a loop that run until the timeout you could just call qApp->processEvents() in the loop, if there's a place you're just waiting you could create a QEventLoop and call it's exec method, just remember to have some way to exit the loop too. Make sure to check the link, it tells you quite a bit about timers, threads and event loops.



  • Ah I see. Thanks so much for your help!


Log in to reply