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

时间:2013-12-19 20:50:09

标签: c++ qt qml

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

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

我做了一些研究,发现QImage提供了一个解决方案,但我没有找到任何解释如何将QUrl信号转换为class Publisher { Q_OBJECT public: Publisher(QObject* parent = 0); virtual ~Publisher(void); Q_SIGNALS: void newImage(const QImage& newImage); }; 的文档用于绘图。任何示例代码或参考文档将不胜感激。

感谢您的帮助!

EDIT1:

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

EDIT2。这是标题。实施应该不重要。

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

编辑3.这是我的QML代码,但我不知道如何绘制我的QImage,所以这段代码毫无意义。

我的main.cpp文件

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
            }
        }
    }
}

我的main.qml文件

{{1}}

4 个答案:

答案 0 :(得分:36)

换句话说,你有一个类发出一个携带QImage的信号,并希望用该图像更新QML中的项目?有各种解决方案,其中没有一个涉及“将QImage转换为QUrl”(无论这意味着,当然您不需要获取带有图像数据的data URL ...)

使用图像提供程序

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

  1. 创建一个QQuickImageProvider子类;给它一个QImage成员(提供者的图像),覆盖requestImage以提供该图像(请求的实际id并不重要,见下文),以及接收一个QImage并更新该成员。
  2. 将您的Publisher信号连接到提供商的广告位
  3. 通过QQmlEngine::addImageProvider将提供者安装到QML引擎中(参见QQuickView::engine);再次id并不重要,只需使用合理的
  4. 在QML中,只需使用带有此类

    的源的普通Image元素
    Image {
        id: myImage
        source: "image://providerIdPassedToAddImageProvider/foobar"
    }
    

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

  5. 我们几乎就在那里,我们现在只需要一种方法推送图像更新到QML世界(否则Image永远不知道何时更新自己)。有关如何使用Connections元素和一些JS执行此操作,请参阅my answer here

    请注意,通常您不需要使Publisher成为QML类型,您只需要在C ++中创建一个实例并通过{{1将其公开给QML世界}}

  6. 使用自定义Qt Quick 2项目

    QQmlContext::setContextProperty可能是最方便的工作,因为它提供了采用QQuickPaintedItem的{​​{1}}方法。因此,重大计划是

    1. 子类paint:子类存储要绘制的QPainter,并且有一个设置新QImage的插槽。此外,其QQuickPaintedItem实现仅使用QImage绘制图像。
    2. 通过paint将子类暴露给QML世界(以便您可以在QML中使用它)
    3. 找出将携带新图像的信号连接到项目插槽的方法。

      这可能是棘手的部分。

      要在C ++中执行连接,您需要一种方法来确定项目是否已创建(并获取指向它的指针);通常通过将QPainter::drawImage属性赋值给某个值,然后在根对象上使用qmlRegisterType(由objectName返回)来获取指向项本身的指针。然后你可以像往常一样使用findChild

      ,可以通过QML世界中发布者C ++对象上的QQuickView::rootObject()元素在QML中执行连接,如上所述:

      connect

      无论何时创建MyItem实例,这都具有工作优势;但我不能100%确定它会起作用,因为我不确定你能否在QML中处理Connections类型。

答案 1 :(得分:3)

当我有想要嵌入QML的图像生成C ++类时,我总是通过使C ++类成为QDeclarativeItem的子类来实现它(将会有一个新的QtQuick 2.0)相当于当然),用适当的绘图代码覆盖paint方法,这可能就像

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

如果你已经有一个正确尺寸的QImage ......和Job Done。对于动画,只要在绘制新内容时ping update()。

答案 2 :(得分:0)

使用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

appendChildNode与QSGSimpleTextureNode

在QML中添加

import Spinner 1.0

Spinner {
    anchors.centerIn: parent
    anchors.horizontalCenterOffset: 80
    spinning: true
}

答案 3 :(得分:0)

QString getImage()
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
img.save(&buffer,"JPEG");
 //save image data in string
QString image("data:image/jpg;base64,");
image.append(QString::fromLatin1(byteArray.toBase64().data()));
return image;
}

将图像字符串直接发送到qml源