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
之前显示的第一张图像。
例如,如果您使用QTimer
或QThread
,您将检查图像是否正确更新。
例子:
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 图像不会在源更改和信号接收时刷新的主要内容,如果未能解决你的问题,请参考以下文章
Webpack 开发服务器 + React + Typescript 在源更改后不会注入资产