Qt / QML:将QImage从C ++发送到QML并在GUI上显示QImage

Qt/QML : Send QImage From C++ to QML and Display The QImage On GUI

我创建了一个类Publisher,该类定期发出QImage对象。

但是,我很难将QImage绘制到QML元素上。看来ImageCanvas QML组件需要QUrl而不是QImage,但是我不确定如何将QImage转换为QUrl。 Edit4:当我说QUrl时,我并不是说我正在尝试将图像转换为URL。废话我的意思是我想生成对此映像的引用,该引用不在磁盘上,并且QML组件要求的数据类型是URL。

我已经进行了一些研究,发现QQuickImageProvider提供了一种解决方案,但是我还没有找到任何文档说明如何将QImage信号转换为可用于绘图的QUrl。任何示例代码或参考文档将不胜感激。

谢谢你的帮助!

编辑1:

我在这里看了一下:http://qt-project.org/doc/qt-5.0/qtquick/qquickimageprovider.html,但我看不到如何将QImage传递给快速图像提供程序并从中创建QUrl 。

编辑2。这是标题。实施不重要。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Publisher
{
    Q_OBJECT

public:
    Publisher(QObject* parent = 0);

    virtual ~Publisher(void);

Q_SIGNALS:

    void newImage(const QImage& newImage);
};

编辑3。这是我的QML代码,但是我不知道如何绘制QImage,因此该代码毫无意义。

我的main.cpp文件:

1
2
3
4
5
6
7
8
9
10
11
12
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文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
            }
        }
    }
}


换句话说,您有一个类发出一个携带QImage的信号,并想用该图像更新QML中的项目?有多种解决方案,都不涉及"将QImage转换为QUrl"(无论这意味着,您肯定不需要获取携带图像数据的data URL ...)

使用图像提供者

这意味着您可以在QML文件中使用普通的Image项目。

  • 创建一个QQuickImageProvider子类;给它一个QImage成员(提供者的映像),覆盖requestImage以提供该映像(所请求的实际id并不重要,请参阅下文),以及一个接收QImage并更新会员。
  • Publisher信号连接到提供商的插槽
  • 通过QQmlEngine::addImageProvider将提供程序安装到QML引擎中(请参见QQuickView::engine);同样,id并不重要,只使用一个明智的
  • 在QML中,只需将普通的Image元素与这样的源一起使用

    1
    2
    3
    4
    Image {
        id: myImage
        source:"image://providerIdPassedToAddImageProvider/foobar"
    }

    foobar将被传递给您的提供者,但同样,这并不重要。

  • 我们快到了,我们现在只需要一种将映像更新推送到QML世界的方法(否则Image将永远不知道何时更新自身)。有关如何使用Connections元素和一些JS做到这一点的信息,请参见这里的答案。

    请注意,通常不需要将Publisher设置为QML类型,只需在C ++中创建一个实例,然后通过QQmlContext::setContextProperty将其公开给QML。

  • 使用自定义Qt Quick 2项目

    QQuickPaintedItem可能是最方便的工作,因为它提供了采用QPainterpaint方法。因此,大计划是

  • 子类QQuickPaintedItem:子类存储要绘制的QImage,并具有用于设置新QImage的插槽。同样,其paint实现仅使用QPainter::drawImage绘制图像。
  • 通过qmlRegisterType将子类公开到QML世界(以便可以在QML中使用它)
  • 找出将携带新图像的信号连接到物品插槽的方法。

    这可能是棘手的部分。

    要使用C ++执行连接,您需要一种方法来确定该项目已创建(并获得指向它的指针);通常,这是通过将objectName属性分配给某个值,然后在根对象(由QQuickView::rootObject()返回)上使用findChild来获得指向项本身的指针来实现的。然后,您可以照常使用connect

    或者,可以像上面一样,通过暴露给QML世界的发布者C ++对象上的Connections元素在QML中执行连接:

    1
    2
    3
    4
    5
    6
    7
    8
    MyItem {
        id: myItem
    }        

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

    无论您何时创建MyItem实例,这都具有工作优势。但我不确定100%会成功,因为我不确定您是否可以处理QML中的QImage类型。


  • 当我想将图像生成的C ++类嵌入到QML中时,我总是通过将C ++类作为QDeclarativeItem的子类来实现的(当然会有一个新的QtQuick 2.0等效项),用适当的绘图代码覆盖paint方法,可能就像这样简单

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

    如果您已经有合适尺寸的QImage ...并完成了作业。对于动画,只需绘制新内容即可ping update()。


    使用QQuickItem。有一个Qt示例可以做到这一点。

    C:\ Qt \ Examples \ Qt-5.14.1 \ quick \ scenegraph \ threadedanimation

    您可以从QQuickItem派生一个类,并使用qmlRegisterType注册它。
    在您的类中提供覆盖函数'updatePaintNode'。在示例中,类为" Spinner"

    在updatePaintNode中:

    创建从QObject和QSGTransformNode派生的节点类

    在节点类构造函数中:

    使用createTextureFromImage将Qimage转换为QSGTexture。

    创建QSGSimpleTextureNode,使用setTexture设置QSGTexture

    具有QSGSimpleTextureNode的appendChildNode

    在QML中添加

    1
    import Spinner 1.0

    1
    2
    3
    4
    5
    Spinner {
        anchors.centerIn: parent
        anchors.horizontalCenterOffset: 80
        spinning: true
    }