Подтвердить что ты не робот

Qt/QML: отправить QImage из С++ в QML и отобразить QImage On GUI

Я создал класс Publisher, который периодически испускает объект QImage.

Однако мне сложно провести рисунок QImage в элементе QML. Похоже, что компоненты Image и Canvas QML требуют QUrl вместо QImage, но я не уверен, как преобразовать my QImage в QUrl. Edit4: Когда я говорю QUrl, я не имею в виду, что я пытаюсь преобразовать изображение в URL. Это вздор. Я имею в виду, что хочу создать ссылку на это изображение, которое не находится на диске, а тип данных, который запрашиваются компонентами QML, - это URL-адрес.

Я провел некоторое исследование и обнаружил, что QQuickImageProvider предоставляет решение, но я не нашел никакой документации, объясняющей, как преобразовать мой сигнал QImage в QUrl, который я могу использовать для рисования. Любой пример кода или справочная документация будут оценены.

Спасибо за вашу помощь!

Edit1:

Я посмотрел здесь: http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html, и я не вижу, как я передаю QImage поставщику быстрых изображений и из него создаю QUrl.

Edit2. Вот заголовок. Реализация не должна быть важной.

class Publisher
{
    Q_OBJECT

public:
    Publisher(QObject* parent = 0);

    virtual ~Publisher(void);

Q_SIGNALS:

    void newImage(const QImage& newImage);
};

Изменить 3. Вот мой QML-код, но я не знаю, как рисовать мой QImage, поэтому этот код не имеет смысла.

мой файл main.cpp:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    qmlRegisterType<Publisher>("Components", 1, 0, "Publisher");

    QtQuick2ApplicationViewer viewer;
    viewer.setMainQmlFile(QStringLiteral("qml/QQuickViewExample/main.qml"));
    viewer.showExpanded();

    return app.exec();
}

мой файл main.qml:

import QtQuick 2.0
import Components 1.0

Rectangle {
    id : testRect
    width: 360
    height: 360

    Image{
        anchors.fill: parent
        id: myImage

        Publisher {
            id: myPub

            onNewImage: {
                myImage.source = newImage;  #I know this doesnt work, it needs a QUrl and not a QImage
            }
        }
    }
}
4b9b3361

Ответ 1

Другими словами, у вас есть класс, излучающий сигнал, несущий QImage, и хотите обновить элемент в QML с этим изображением? Существуют различные решения, ни одна из которых не включает в себя "преобразование QImage в QUrl" (независимо от того, что это означает, конечно, вам не нужно получать URL data, несущий ваши данные изображения...)

Использование поставщика изображений

Это означает, что вы можете использовать простой Image элемент в ваших файлах QML.

  • Создайте подкласс QQuickImageProvider; дать ему элемент QImage (изображение для провайдера), переопределить requestImage, чтобы обеспечить это изображение (фактический id запрос не имеет значения, см. ниже) и слот, который получает QImage, и обновляет член.
  • Подключите свой Publisher сигнал к слоту вашего провайдера.
  • Установите поставщика в механизм QML с помощью QQmlEngine::addImageProvider (см. QQuickView::engine); снова id не имеет большого значения, просто используйте разумный
  • В QML просто используйте простой элемент Image с источником вроде этого

    Image {
        id: myImage
        source: "image://providerIdPassedToAddImageProvider/foobar"
    }
    

    foobar будет передан вашему провайдеру, но опять же, это не имеет большого значения.

  • Мы почти там, теперь нам нужен способ нажимать обновления изображений в мир QML (иначе изображение никогда не узнает, когда нужно обновить себя). См. мой ответ здесь о том, как это сделать с помощью элемента Connections и немного JS.

    Обратите внимание, что в общем случае вам не нужно делать Publisher тип QML, вам просто нужно создать один экземпляр на С++ и выставить его в мир QML через QQmlContext::setContextProperty.

Использовать пользовательский Qt Quick 2 Item

QQuickPaintedItem, вероятно, наиболее удобен для работы, поскольку он предлагает метод paint, принимающий QPainter. Следовательно, большой план

  • Подкласс QQuickPaintedItem: подкласс хранит QImage для окрашивания и имеет слот, который устанавливает новый QImage. Также реализация paint просто рисует изображение с помощью QPainter::drawImage.
  • Предоставьте подкласс миру QML через qmlRegisterType (чтобы вы могли использовать его в QML)
  • Выясните способ подключения сигнала, несущего новое изображение, к слоту.

    Это может быть сложная часть.

    Чтобы выполнить соединение на С++, вам нужно выяснить, что элемент был создан (и получить указатель на него); обычно это делается путем присвоения свойству objectName некоторому значению, а затем с помощью findChild в корневом объекте (возвращаемом QQuickView::rootObject()), чтобы получить указатель на сам элемент. Затем вы можете использовать connect, как обычно.

    Или вместо этого можно выполнить соединение в QML, как и выше, с помощью элемента Connections объекта издателя С++, открытого в мире QML:

    MyItem {
        id: myItem
    }        
    
    Connections {
        target: thePublisherObjectExposedFromC++
        onNewImage: myItem.setImage(image)
    }
    

    Это имеет то преимущество, что вы работаете независимо от того, когда вы создаете экземпляр MyItem; но я не уверен на 100%, что он будет работать, потому что я не уверен, что вы можете обрабатывать тип QImage в QML.

Ответ 2

Когда у меня были классы С++ для создания образов, которые я хотел встроить в QML, я всегда делал это, делая класс С++ подклассом QDeclarativeItem (будет новый эквивалент QtQuick 2.0 курс), переопределяя метод рисования с помощью соответствующего кода чертежа, который может быть таким же простым, как

void MyItem::paint(QPainter* painter,const QStyleOptionGraphicsItem*,QWidget*) {
  painter->drawImage(QPointF(0.0f,0.0f),_image);
}

если у вас уже есть QImage нужного размера... и Job Done. Для анимации просто ping update(), когда есть что-то новое для рисования.