Обновление изображения с C ++ до QML - PullRequest
0 голосов
/ 28 мая 2018

Я пытаюсь обновить QImage с c ++ до QML,

Я использую подход из: https://www.huber.xyz/?p=477

Я реализовал QQuickPaintedItem - показывается начальный QImage, но яне могу найти способ обновить QImage из c ++, если я получаю там сигнал (FileWatcher).

Моя реализация выглядит следующим образом:

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

Как я могу получить ссылку на ImageItem на стороне c ++ для управления обновлением изображения черезsetImage?

Возможен ли этот способ или я должен попробовать другое решение?

Я пытался получить элемент по

QList<ImageItem*> res = engine->findChildren<ImageItem*>();

, а также:

QList<ImageItem*> res = engine->findChildren<ImageItem*>("liveImageItem");

список ImageItems (res) всегда пуст.

Ответы [ 2 ]

0 голосов
/ 19 марта 2019

Чтобы немного улучшить решение @ 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
}
0 голосов
/ 28 мая 2018

В общем, вам следует избегать изменения элемента, созданного в QML непосредственно из C ++, перед этим я улучшу вашу реализацию, добавив изображение как 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();
}

Для меня лучшая идея - реализовать помощник и установить соединение в 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
}
...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...