如何从QML更新QPaintedTextureImage子类-对象QPaintedTextureImage的属性'update'不是函数

时间:2019-01-31 22:01:17

标签: qt qml qpainter qt3d

我想在Qt3D中(通过纹理)显示来自捕获设备的图像流。

所以我将QPaintedTextureImage归为子类:

#include <Qt3DRender/QPaintedTextureImage>
#include <QPainter>
#include <QImage>
#include <QPaintDevice>
#include <opencv2/opencv.hpp>

class OpenCVCaptureImage : public Qt3DRender::QPaintedTextureImage
{
public:
    explicit OpenCVCaptureImage(Qt3DCore::QNode *parent = nullptr);
    void paint(QPainter *painter) override;

private:
    cv::VideoCapture cap_;
};

OpenCVCaptureImage::OpenCVCaptureImage(Qt3DCore::QNode *parent)
    : Qt3DRender::QPaintedTextureImage(parent),
      cap_(0)
{
}

void OpenCVCaptureImage::paint(QPainter *painter)
{
    cv::Mat frame;
    cap_ >> frame;
    QImage im(static_cast<uchar *>(frame.data), frame.cols, frame.rows, int(frame.step), QImage::Format_RGB888);
    if(im.isNull()) return;
    setSize(im.size());
    //int w = painter->device()->width();
    //int h = painter->device()->height();
    painter->drawImage(0, 0, im);
}

根据documentation

  

必须QPaintedTextureImage的子类,并且必须实现虚拟paint()函数。每次在QPaintedTextureImage上调用update()时,都会调用paint()函数并上传结果图像。

因此我在场景树中添加了Timer,并在onTriggered插槽中调用了capImage.update(),但是在运行时出现了问题:

2019-01-31 22:48:54.865282 + 0100 Qt3DOpenCV [50001:4569220] qrc:/MyScene.qml:57:TypeError:Object Qt3DRender :: QPaintedTextureImage(0x106ef6bf0的属性'update' )不是功能

main.cpp:

#include <QGuiApplication>
#include <Qt3DQuickExtras/qt3dquickwindow.h>
#include "opencvcaptureimage.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    qmlRegisterType<OpenCVCaptureImage>("OpenCVCaptureImage", 1, 0, "OpenCVCaptureImage");

    QGuiApplication app(argc, argv);

    Qt3DExtras::Quick::Qt3DQuickWindow view;
    view.setSource(QUrl("qrc:/MyScene.qml"));
    view.show();

    return app.exec();
}

MyScene.qml:

import Qt3D.Core 2.0
import Qt3D.Render 2.0
import Qt3D.Input 2.0
import Qt3D.Extras 2.0
import OpenCVCaptureImage 1.0
import QtQml 2.12

Entity {
    id: sceneRoot

    RenderSettings {
        id: renderSettings
        activeFrameGraph: ForwardRenderer {
            clearColor: Qt.rgba(0, 0.5, 1, 1)
            camera: Camera {
                id: objectsCamera
                projectionType: CameraLens.PerspectiveProjection
                fieldOfView: 45
                aspectRatio: 16/9
                nearPlane : 0.1
                farPlane : 1000.0
                position: Qt.vector3d( 0.0, 0.0, -40.0 )
                upVector: Qt.vector3d( 0.0, 1.0, 0.0 )
                viewCenter: Qt.vector3d( 0.0, 0.0, 0.0 )
            }
        }
    }

    InputSettings {
        id: inputSettings
    }

    components: [renderSettings, inputSettings]

    PlaneMesh {
        id: planeMesh
        width: 2
        height: 2
    }

    TextureMaterial {
        id: planeMaterial
        texture: Texture2D {
            id: planeTexture
            textureImages: [
                OpenCVCaptureImage {
                    id: capImage
                }
            ]
        }
    }

    Timer {
        interval: 500
        running: true
        repeat: true
        onTriggered: capImage.update()
    }

    Transform {
        id: planeTransform
        rotationX: 90
    }

    Entity {
        id: planeEntity
        components: [ planeMesh, planeMaterial, planeTransform ]
    }
}

编辑:我还尝试将计时器放入C ++构造函数中

OpenCVCaptureImage::OpenCVCaptureImage(Qt3DCore::QNode *parent)
    : Qt3DRender::QPaintedTextureImage(parent),
      cap_(0)
{
    QTimer::singleShot(2500, [=] {
        auto t = new QTimer(this);
        connect(t, &QTimer::timeout, [=] {
            this->update();
        });
        t->setInterval(200);
        t->start();
    });
}

在这种情况下,程序在QPainter::drawImage中崩溃,并且此错误被打印到控制台:

2019-02-01 11:15:45.754907 + 0100 Qt3DOpenCV [55788:4839633] QPaintDevice:无法销毁正在绘制的绘制设备

1 个答案:

答案 0 :(得分:0)

我不太确定自己在做什么错,但是我在this example中成功使用了QPaintedTextureImage并添加了一个计时器,该计时器可以定期更新纹理。 Qt3D不会直接调用它,但是您可以像您在问题中建议的那样进行调用。也许尝试清理项目,然后运行qmake并随后进行构建。