Qml 图像不会在源更改和信号接收时刷新

Posted

技术标签:

【中文标题】Qml 图像不会在源更改和信号接收时刷新【英文标题】:Qml Image doesn't refresh on source change and signal reception 【发布时间】:2016-03-25 15:11:50 【问题描述】:

我在 Qt Creator bt 中创建了“fruit_swap”项目,选择--应用程序-> Qt 快速应用程序-> Qt 5.5。 在fruit_swap 中,'main()' 函数调用 forkSwapper(),它分叉了一个每秒交换一次水果图像(苹果 梨)的进程。

交换是在 setImageURL() 方法中完成的,该方法也为 qml 发出“imageURLChanged”信号。从输出(如下图底部)可以看出,信号被传递到了 qml 端。

我期待 qml 图像交换。然而,它没有。显示的第一张图片('pear')一动不动。我做错了什么?欢迎任何建议。我上传了下面的每一个源代码。

fruit_swap.pro

/* 由 Qt Creator 生成 */

TEMPLATE = app

QT += qml quick
CONFIG += c++11

SOURCES += main.cpp \
    imageitem.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Default rules for deployment.
include(deployment.pri)

HEADERS += \
    imageitem.h

DISTFILES += \
    FruitFrame.qml

imageitem.h

/* https://quickgit.kde.org/?p=scratch%2Fsune%2Fimageitem.git */

#include <QQuickPaintedItem>
/**
 * @brief QQuickItem to show images/pixmaps/colors in a QML item
 *
 * As opposed to the Image from plain qml, this works on
 * QImages, QPixmaps and QColors
 */
class ImageItem : public QQuickPaintedItem

//        Q_PROPERTY(QVariant imageData READ imageData() WRITE setImageData
//                   NOTIFY imageDataChanged)
        Q_OBJECT
        Q_PROPERTY(QVariant imageURL READ imageURL() WRITE setImageURL
                   NOTIFY imageURLChanged)
    public:
        explicit ImageItem(QQuickItem *parent = 0);
        /**
         * \reimpl
         */
        Q_INVOKABLE void paint(QPainter* painter) Q_DECL_OVERRIDE;
        /**
         * @brief image data u-ed by this item
         * @return a QVariant wrapping the data
         */
        QVariant imageData() const;
        /**
         * @brief Sets the image data
         * @param newData
         */
        void setImageData(const QVariant& newData);

        QVariant imageURL() const;
        /**
         * @brief Sets the image data
         * @param newData
         */
        void setImageURL(const QVariant& fileName);
    Q_SIGNALS:
        /**
         * @brief imageChanged
         */
        void imageDataChanged();
        void imageURLChanged();

    private:
        enum Type 
            Unknown,
            Pixmap,
            Image,
            Color
        ;
        Type m_type;
        QVariant m_imageData;
        QVariant m_imageURL;
        QRectF scaledRect(const QRect& sourceRect) const;
;
#endif // IMAGEITEM_H

imageitem.cpp

/* https://quickgit.kde.org/?p=scratch%2Fsune%2Fimageitem.git */

#include "imageitem.h"
#include <QPainter>
#include <qobjectdefs.h>

ImageItem::ImageItem(QQuickItem *parent) :
    QQuickPaintedItem(parent)

    m_imageURL = QUrl::fromLocalFile(QString("apple.jpg"));


void ImageItem::paint(QPainter* painter)

    switch(m_type) 
        case Unknown: 
            return;
        
        case Image: 
            QImage image = m_imageData.value<QImage>();
            painter->drawImage(scaledRect(image.rect()), image);
            return;
        
        case Pixmap: 
            QPixmap pixmap = m_imageData.value<QPixmap>();
            painter->drawPixmap(scaledRect(pixmap.rect()).toRect(), pixmap);
            return;
        
        case Color: 
            QColor color = m_imageData.value<QColor>();
            painter->fillRect(contentsBoundingRect(),color);
            return;
        
    


QVariant ImageItem::imageData() const

    return m_imageData;


QVariant ImageItem::imageURL() const

    return m_imageURL;


void ImageItem::setImageURL(const QVariant &fileName)

    m_imageURL = QUrl::fromLocalFile(fileName.value<QString>());
    if (m_imageURL.canConvert<QUrl>()) 
        QUrl url = m_imageURL.value<QUrl>();
        if (!url.isEmpty() && url.isValid()
                && url.isLocalFile())
        
            qDebug() << "URL is valid";
         else 
            qDebug() << "URL is INvalid";
        
     else 
        qDebug() << "URL is INvalid";
    
    emit imageURLChanged();


void ImageItem::setImageData(const QVariant& newData)

    switch(newData.userType()) 
        case QMetaType::QPixmap: 
            m_type = Pixmap;
            break;
        
        case QMetaType::QImage: 
            m_type = Image;
            break;
        
        case QMetaType::QColor: 
            m_type = Color;
            break;
        
        default: 
            m_type = Unknown;
            break;
        
    
    m_imageData = newData;
    emit imageDataChanged();


QRectF ImageItem::scaledRect(const QRect& sourceRect) const

    QRectF targetRect = contentsBoundingRect();

    QSizeF scaledSize;

    double widthScale = targetRect.width() / sourceRect.width();
    double heightScale = targetRect.height() / sourceRect.height();
    if(widthScale < heightScale) 
        scaledSize.setHeight(sourceRect.height() * widthScale);
        scaledSize.setWidth(sourceRect.width() *widthScale);
     else 
        scaledSize.setHeight(sourceRect.height() * heightScale);
        scaledSize.setWidth(sourceRect.width() *heightScale);
    

    QRectF result = QRectF(targetRect.left() + targetRect.width() /2 - scaledSize.width() /2,
                targetRect.top() + targetRect.height()/2 - scaledSize.height()/2,
                scaledSize.width(),scaledSize.height());
//    QRectF result(QPointF(0,0),scaledSize);
    qDebug() << result << targetRect << sourceRect << widthScale << heightScale ;
    return result;

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QImage>
#include <unistd.h>

#include "imageitem.h"

void forkSwapper(ImageItem * fImage);

int main(int argc, char *argv[])

    qmlRegisterType<ImageItem>("ImageItem",1,0,"ImageItem");

    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    ImageItem *fImage = new ImageItem();

    fImage->setImageURL("fruit.jpg");

    engine.rootContext()->setContextProperty("cpp_imageURL", fImage);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    forkSwapper(fImage);

    return app.exec();


void forkSwapper(ImageItem * fImage) 

    int pid = fork();

    if (pid == 0) 
        int i = 0;
        while (true) 
            if (i++ % 2 == 0)
                fImage->setImageURL("apple.jpg");
                //std::system("cp apple.jpg fruit.jpg");
            else
                fImage->setImageURL("pear.jpg");
                //std::system("cp pear.jpg fruit.jpg");

            qDebug() << "fruit image changed";
            sleep(1);
        
        _exit (EXIT_FAILURE);
     else 
        qDebug() << "swapper forked, PID:" << pid;
    

FruitFrame.qml

import QtQuick 2.5
import ImageItem 1.0

Rectangle 
    property alias mouseArea: mouseArea

    width: 360
    height: 360

    MouseArea 
        id: mouseArea
        anchors.fill: parent

        Connections 
            target: cpp_imageURL
            onImageURLChanged: 
                fruit_image.update();
                // fruit_image.source = cpp_imageURL.imageURL;
                console.log("image UURL-" + cpp_imageURL.imageURL);
            
        

        Image 
            id: fruit_image
            x: 39
            y: 94
            width: 274
            height: 204
            source: cpp_imageURL.imageURL
            cache: false
        
    

    Text 
        anchors.centerIn: parent
        text: "Hello World"
        anchors.verticalCenterOffset: -137
        anchors.horizontalCenterOffset: -104
    

main.qml

import QtQuick 2.5
import QtQuick.Window 2.2
import ImageItem 1.0

Window 
    visible: true

    width: 360
    height: 460

    FruitFrame 
        anchors.fill: parent
        mouseArea.onClicked: 
            Qt.quit();
        
    

应用程序输出

Starting /home/jbpark03/wem/fruit_swap/build/fruit_swap...
QML debugging is enabled. Only use this in a safe environment.
URL is valid
URL is valid
qml: image UURL-file:apple.jpg
fruit image changed
swapper forked, PID: 3078
URL is valid
qml: image UURL-file:pear.jpg
fruit image changed
URL is valid
qml: image UURL-file:apple.jpg
fruit image changed
URL is valid
qml: image UURL-file:pear.jpg
fruit image changed
URL is valid
qml: image UURL-file:apple.jpg

结束。

【问题讨论】:

【参考方案1】:

代码运行良好。我认为问题在于您正在阻止 Qt 应用程序,因为您使用的是sleep

事实上,您会看到图像pear.jpg,因为它是在fruit.jpg 之后和任何sleep 之前显示的第一张图像。

例如,如果您使用QTimerQThread,您将检查图像是否正确更新。

例子:

mytimer.h

#ifndef MYTIMER_H
#define MYTIMER_H

#include <QObject>
#include <QTimer>
#include "imageitem.h"

class MyTimer : public QObject

    Q_OBJECT
public:
    explicit MyTimer(ImageItem * fImage, QObject *parent = 0);

private:
    QTimer *timer;
    ImageItem *myImage;

signals:

public slots:
    void update();
;

#endif // MYTIMER_H

mytimer.cpp

#include <QDebug>
#include <QTest>
#include "mytimer.h"

MyTimer::MyTimer(ImageItem * fImage, QObject *parent) : QObject(parent)

    myImage = fImage;
    timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(update()));
        timer->start(1000);


void MyTimer::update()

    myImage->setImageURL(":pear.jpg");

    QTest::qWait(250);

    myImage->setImageURL(":apple.jpg");

使用此计时器,我们将每 1 秒更改一次图像。现在,在我们的main.cpp

#include "mytimer.h"

int main(int argc, char *argv[])

    qmlRegisterType<ImageItem>("ImageItem",1,0,"ImageItem");

    QGuiApplication app(argc, argv);
    QQmlApplicationEngine engine;
    ImageItem *fImage = new ImageItem();
    MyTimer *timer = new MyTimer(fImage);

    fImage->setImageURL(":fruit.jpg");

    engine.rootContext()->setContextProperty("cpp_imageURL", fImage);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();

【讨论】:

太棒了!谢谢你 :) 编码愉快,博士!

以上是关于Qml 图像不会在源更改和信号接收时刷新的主要内容,如果未能解决你的问题,请参考以下文章

如何在属性更改 QML 上实现行为动画

Webpack 开发服务器 + React + Typescript 在源更改后不会注入资产

<object> 标签在 Chrome 中更改其数据属性时不会刷新 [重复]

如何更改 QQuickView 的来源

源更改时刷新图像[重复]

BlackBerry Cascades 中的 QML 字符串