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

tri*_*ta2 28 c++ qt qml

我创建了一个Publisher定期发出QImage对象的类.

但是,我很难将其绘制QImage到QML元素中.似乎ImageCanvasQML组件需要一个QUrl而不是一个QImage,但我不知道如何将我转换QImage成一个QUrl.编辑4:当我说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);
};
Run Code Online (Sandbox Code Playgroud)

编辑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();
}
Run Code Online (Sandbox Code Playgroud)

我的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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

pep*_*ppe 37

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

使用图像提供程序

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

  1. 创建一个QQuickImageProvider子类; 给它一个QImage成员(图像到提供者),覆盖requestImage以提供该图像(实际id请求并不重要,见下文),以及接收QImage和更新成员的插槽.
  2. Publisher信号连接到提供商的插槽
  3. 通过QQmlEngine::addImageProvider(见QQuickView::engine)将提供者安装到QML引擎中; 再次,id这并不重要,只需使用一个明智的
  4. 在QML中,只需使用Image带有这样的源的普通元素

    Image {
        id: myImage
        source: "image://providerIdPassedToAddImageProvider/foobar"
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

  5. 我们几乎就在那里,我们现在只需要一种方法图像更新送到QML世界(否则Image永远不会知道何时更新自己).请参阅我的答案,了解如何使用Connections元素和一些JS 来做到这一点.

    请注意,通常您不需要创建PublisherQML类型,您只需要在C++中创建一个实例并通过它将其公开给QML世界QQmlContext::setContextProperty.

使用自定义Qt Quick 2项目

QQuickPaintedItem这可能是最方便的工作,因为它提供了一种paint方法QPainter.因此,重大计划是

  1. 子类QQuickPaintedItem:子类存储QImage要绘制的子类,并有一个设置新QImage的插槽.它的paint实现也只是使用绘制图像QPainter::drawImage.
  2. 通过qmlRegisterType(因此您可以在QML中使用它)将子类公开给QML世界
  3. 找出一种将携带新图像的信号连接到物品槽的方法.

    这可能是棘手的部分.

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

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

    MyItem {
        id: myItem
    }        
    
    Connections {
        target: thePublisherObjectExposedFromC++
        onNewImage: myItem.setImage(image)
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

  • 方法1似乎不起作用,因为`QQuickImageProvider`不是`QObject`,因此不能有任何插槽.无论如何使用多重继承为它提供插槽似乎也是一个坏主意; MOC不喜欢它. (2认同)

tim*_*day 5

当我拥有想要嵌入 QML 的图像生成 C++ 类时,我总是通过使 C++ 类成为QDeclarativeItem(当然会有一个新的 QtQuick 2.0 等效项)的子类来完成它,覆盖绘制具有适当绘图代码的方法,这可能就像

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

如果你已经有一个合适大小的 QImage ......并且工作完成了。对于动画,只需在有新内容要绘制时 ping update() 即可。

  • `QQuickPaintedItem` 与旧的绘画方法有关。对于新技术和大多数性能,您需要使用`QQuickItem` 并使用纹理。 (2认同)