我正在尝试将QImage从c ++更新为QML,
我使用的方法是:https://www.huber.xyz/?p=477
我实现了QQuickPaintedItem - 显示了初始QImage,但如果我在那里收到信号(FileWatcher),我找不到从c ++更新QImage的方法。
我的实现如下:
QML:
ImageItem {
id: liveImageItem
height: parent.height
width: parent.width
objectName: "liveImageItem"
}
我用以下方式注册图像:
qmlRegisterType<QUIQImageItem>("imageItem", 1, 0, "ImageItem");
Image的实现:
ImageItem::ImageItem(QQuickItem *parent) : QQuickPaintedItem(parent) {
qDebug() << Q_FUNC_INFO << "initializing new item, parent is: " << parent;
this->current_image = QImage(":/resources/images/logo.png");
}
void ImageItem::paint(QPainter *painter) {
qDebug() << Q_FUNC_INFO << "paint requested...";
QRectF bounding_rect = boundingRect();
QImage scaled = this->current_image.scaledToHeight(bounding_rect.height());
QPointF center = bounding_rect.center() - scaled.rect().center();
if (center.x() < 0)
center.setX(0);
if (center.y() < 0)
center.setY(0);
painter->drawImage(center, scaled);
}
QImage ImageItem::image() const {
qDebug() << Q_FUNC_INFO << "image requested...";
return this->current_image;
}
void ImageItem::setImage(const QImage &image) {
qDebug() << Q_FUNC_INFO << "setting new image...";
this->current_image = image;
emit imageChanged();
update();
}
如何在c ++端获取ImageItem的引用来通过setImage管理Image的更新?
这种方式是否可行,还是应该尝试其他解决方案?
我试图通过
获取该项目QList<ImageItem*> res = engine->findChildren<ImageItem*>();
还有:
QList<ImageItem*> res = engine->findChildren<ImageItem*>("liveImageItem");
ImageItems(res)列表始终为空。
答案 0 :(得分:1)
一般来说,你应该避免直接从C ++修改用QML创建的项目,然后我会通过将图像添加为qproperty来改进你的实现:
<强> *的.h 强>
#ifndef IMAGEITEM_H
#define IMAGEITEM_H
#include <QImage>
#include <QQuickPaintedItem>
class ImageItem : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QImage image READ image WRITE setImage NOTIFY imageChanged)
public:
ImageItem(QQuickItem *parent = nullptr);
QImage image() const;
void setImage(const QImage &image);
void paint(QPainter *painter);
signals:
void imageChanged();
private:
QImage m_image;
};
#endif // IMAGEITEM_H
<强> *。CPP 强>
#include "imageitem.h"
#include <QDebug>
#include <QPainter>
ImageItem::ImageItem(QQuickItem *parent):QQuickPaintedItem(parent)
{
qDebug() << Q_FUNC_INFO << "initializing new item, parent is: " << parent;
setImage(QImage(":/resources/images/logo.png"));
}
QImage ImageItem::image() const
{
qDebug() << Q_FUNC_INFO << "image requested...";
return m_image;
}
void ImageItem::setImage(const QImage &image)
{
qDebug() << Q_FUNC_INFO << "setting new image...";
if(image == m_image)
return;
m_image = image;
emit imageChanged();
update();
}
void ImageItem::paint(QPainter *painter)
{
if(m_image.isNull())
return;
qDebug() << Q_FUNC_INFO << "paint requested...";
QRectF bounding_rect = boundingRect();
QImage scaled = m_image.scaledToHeight(bounding_rect.height());
QPointF center = bounding_rect.center() - scaled.rect().center();
if (center.x() < 0)
center.setX(0);
if (center.y() < 0)
center.setY(0);
painter->drawImage(center, scaled);
}
在这部分中,我将回答您的直接问题,虽然它不是最好的,因为如果您不知道如何处理,您可能会遇到问题,例如,如果您在StackView
页面中设置项目,因为它们每次更改页面时都会创建和删除。
QObject *obj = engine.rootObjects().first()->findChild<QObject*>("liveImageItem");
if(obj){
QImage image = ...;
QQmlProperty::write(obj, "image", image);
}
实施例: 的的main.cpp 强>
#include "imageitem.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QTime>
#include <QTimer>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
qsrand(QTime::currentTime().msec());
qmlRegisterType<ImageItem>("com.eyllanesc.org", 1, 0, "ImageItem");
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QObject *obj = engine.rootObjects().first()->findChild<QObject*>("liveImageItem");
QTimer timer;
if(obj){
QObject::connect(&timer, &QTimer::timeout, [obj](){
QImage image(100,100, QImage::Format_ARGB32);
image.fill(QColor(qrand()%255, qrand()%255, qrand()%255));
QQmlProperty::write(obj, "image", image);
});
timer.start(1000);
}
return app.exec();
}
对我来说,更好的想法是实现一个Helper并在QML中建立连接:
#include "imageitem.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlProperty>
#include <QQmlContext>
#include <QTime>
#include <QTimer>
class Helper: public QObject{
Q_OBJECT
Q_PROPERTY(QImage image READ image WRITE setImage NOTIFY imageChanged)
public:
QImage image() const{ return m_image; }
void setImage(const QImage &image){
if(m_image == image)
return;
m_image = image;
emit imageChanged();
}
signals:
void imageChanged();
private:
QImage m_image;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
qsrand(QTime::currentTime().msec());
qmlRegisterType<ImageItem>("com.eyllanesc.org", 1, 0, "ImageItem");
QGuiApplication app(argc, argv);
Helper helper;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("helper", &helper);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&helper](){
QImage image(100,100, QImage::Format_ARGB32);
image.fill(QColor(qrand()%255, qrand()%255, qrand()%255));
helper.setImage(image);
});
timer.start(1000);
return app.exec();
}
#include "main.moc"
<强> *。QML 强>
...
ImageItem{
id: liveImageItem
height: parent.height
width: parent.width
}
Connections{
target: helper
onImageChanged: liveImageItem.image = helper.image
}
...
答案 1 :(得分:1)
要稍微改进@eyllanesc的解决方案,Helper
类应该保留状态,而ImageItem
应该只是图像的哑表示。
此外,您不需要单独的Connection
元素。
我的设置如下:
LiveImage.h
#ifndef LIVEIMAGE_H
#define LIVEIMAGE_H
#include <QImage>
#include <QQuickPaintedItem>
#include <QPainter>
class LiveImage : public QQuickPaintedItem
{
Q_OBJECT
Q_PROPERTY(QImage image MEMBER m_image WRITE setImage)
// Just storage for the image
QImage m_image;
public:
explicit LiveImage(QQuickItem *parent = nullptr);
void setImage(const QImage &image);
void paint(QPainter *painter) override;
};
#endif // LIVEIMAGE_H
LiveImage.cpp
#include "LiveImage.h"
LiveImage::LiveImage(QQuickItem *parent) : QQuickPaintedItem(parent), m_image{}
{}
void LiveImage::paint(QPainter *painter)
{
painter->drawImage(0, 0, m_image);
}
void LiveImage::setImage(const QImage &image)
{
// Update the image
m_image = image;
// Redraw the image
update();
}
ImageProvider.h
#ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H
#include <QObject>
#include <QImage>
class ImageProvider : public QObject
{
Q_OBJECT
Q_PROPERTY(QImage image MEMBER m_image READ image WRITE setImage NOTIFY imageChanged)
QImage m_image;
public:
explicit ImageProvider(QObject *parent = nullptr);
void setImage(QImage const &image);
QImage image() const;
signals:
void imageChanged();
};
#endif // IMAGEPROVIDER_H
ImageProvider.cpp
#include "ImageProvider.h"
ImageProvider::ImageProvider(QObject *parent)
: QObject(parent)
{}
void ImageProvider::setImage(QImage const &image)
{
m_image = image;
emit imageChanged();
}
QImage ImageProvider::image() const
{
return m_image;
}
然后在您的main
函数中,将LiveImage
注册为可实例化的QML类型,并使ImageProvider
的实例也可从QML使用:
qmlRegisterType<LiveImage>("MyApp.Images", 1, 0, "LiveImage");
ImageProvider provider{};
engine.rootContext()->setContextProperty("LiveImageProvider", &provider);
QTimer::singleShot(1000, [&provider](){
QImage image{480, 480, QImage::Format_ARGB32};
image.fill(Qt::yellow);
provider.setImage(std::move(image));
});
最后,您的QML如下所示:
import MyApp.Images
...
LiveImage {
width: 480
height: 480
x: 0
y: 0
image: LiveImageProvider.image
}