1

因此,我检查了以下问题,这些问题似乎与我现有的问题最相似:

QML:在 QML 中使用 cpp 信号总是导致“无法分配给不存在的属性”

不幸的是,这并没有帮助。(我在 stackoverflow/google/qt 论坛等上也找不到任何其他解决方案)

我不断收到以下两个错误:

qrc:/view.qml:30:9:QML 连接:无法分配给不存在的属性“onNewFrameReceived” qrc:/view.qml:31:ReferenceError:未定义 imageProvide

这是我的代码(经过编辑使其成为“最小工作示例”)。

唯一重要的文件应该是:

  1. 主文件
  2. 视图.qml
  3. imageprovidervm.cpp
  4. imageprovidervm.h

我包含了imagesource类,只是为了完整,以防有人也想自己编译它。

Q1。所以,我不明白为什么即使在main.cpp中设置了 context 属性,也会出现以下错误。

qrc:/view.qml:31: ReferenceError: imageProvide 未定义

有趣的是,智能感知/自动完成似乎完全正确地检测到了 imageProvide。

Q2。即使在我的imageprovider.h中,我添加了应该在 qml 文件中看到的属性 (newimage) 和信号 (newFrameReceived),但我仍然收到以下错误。此外,Qt 智能感知/自动完成无法在此处显示我定义的信号 (onNewFrameReceived)。

qrc:/view.qml:30:9:QML 连接:无法分配给不存在的属性“onNewFrameReceived”

  • 附加信息:在第 31 行的 qml 文件中的断点处调试和停止,在 qtcreator 的“局部变量和表达式”中显示我这里只有 2 个可用信号,即“ objectNameChanged ”和“ targetChanged ”。为什么 ???

主文件

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "imageprovidervm.h"
#include "imagesource.h"

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

        QQmlApplicationEngine engine;
        QQmlContext *context = new QQmlContext(engine.rootContext());

        auto model = std::make_shared<ImageSource>();

        auto vm = new ImageProviderVM(model);
        engine.addImageProvider(QLatin1String("imageProvider"), vm);
        context->setContextProperty("imageProvide", vm );

        model->generateImages();

        engine.load(QUrl(QStringLiteral("qrc:/view.qml")));

        return app.exec();
    }

视图.qml

import QtQuick 2.5
import QtQuick.Controls 1.4

import QtQml.Models 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Window 2.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    menuBar: MenuBar {
        Menu {
            title: qsTr("File")
            MenuItem {
                text: qsTr("&Open")
                onTriggered: console.log("Open action triggered");
            }
            MenuItem {
                text: qsTr("Exit")
                onTriggered: Qt.quit();
            }
        }
    }

    Rectangle {
        Connections {
            target: imageProvide
            onNewFrameReceived: image.reload();
        }
        anchors.fill: parent
        Column {
            Image {
                id: image
                source: "image://imageProvider/images.jpeg?id=" + Math.random()
                cache: false
                asynchronous: true
                function reload() {
                        var oldSource = source;
                        source = "";
                        source = oldSource;
                    }
            }
        }
    }
    Label {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }
}

imageprovidervm.h

#ifndef IMAGEPROVIDERVM_H
#define IMAGEPROVIDERVM_H

#include <QQuickImageProvider>
#include <QObject>
#include "imagesource.h"

class ImageProviderVM : public QObject, public QQuickImageProvider
{
    Q_OBJECT
public:
    ImageProviderVM(std::shared_ptr<ImageSource> model);
    ~ImageProviderVM();

    virtual QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
    virtual QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize) override;

    // Properties
    Q_PROPERTY(QImage newimage READ getNewImage NOTIFY newFrameReceived)

    // Signals
signals:
    void newFrameReceived();

private:
    QImage getNewImage() const;

    QPixmap m_pixmap;
    QImage m_image;

    std::shared_ptr<ImageSource> m_model;
};

#endif // IMAGEPROVIDERVM_H

imageprovidervm.cpp

#include "imageprovidervm.h"
#include <functional>

#include <QPixmap>
#include <QDebug>

ImageProviderVM::ImageProviderVM()
    : QQuickImageProvider(QQuickImageProvider::Image)
{
}

ImageProviderVM::ImageProviderVM(std::shared_ptr<ImageSource> model)
    : QQuickImageProvider (QQuickImageProvider::Image)
    , m_pixmap()
    , m_model(model)
{
    m_model->subscribeNewPixMap([this](QPixmap pixmap) {
        qDebug() << "setting m_pixmap";
        if (pixmap.size().isValid()) {
            m_pixmap = pixmap;
        }
        else
            qDebug() << "is it NULL ??? " << pixmap.isNull();
    });

    m_model->subscribeNewImage([this](QImage image) {
        qDebug() << "setting m_image";
        if (image.size().isValid()) {
            m_image = image;
            emit newFrameReceived();
        }
        else
            qDebug() << "is it NULL ??? " << image.isNull();
    });

    qDebug() << "imageproviderVM constructed";
}

ImageProviderVM::~ImageProviderVM()
{
}

QPixmap ImageProviderVM::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
    // look into the parameters id, size and requestedSize once the rest of the structure is there
    return m_pixmap;
}

QImage ImageProviderVM::requestImage(const QString & id, QSize * size, const QSize & requestedSize)
{
    return m_image;
}

QQuickTextureFactory * ImageProviderVM::requestTexture(const QString & id, QSize * size, const QSize & requestedSize)
{
//    return QQuickTextureFactory::createTexture();
}

QImage ImageProviderVM::getNewImage() const
{
    return m_image;
}

图像源.h

#ifndef IMAGESOURCE_H
#define IMAGESOURCE_H

#include <QImage>
#include <boost/signals2.hpp>

class ImageSource
{
public:
    ImageSource();
    void generateImages();
    void generatePixmaps(const QString &id, QSize *size, const QSize &requestedSize);

    typedef boost::signals2::signal<void (QPixmap)> NewPixMapDelegate;
    boost::signals2::connection subscribeNewPixMap(NewPixMapDelegate::slot_function_type f);

    typedef boost::signals2::signal<void (QImage)> NewImageDelegate;
    boost::signals2::connection subscribeNewImage(NewImageDelegate::slot_function_type f);


private:
    NewPixMapDelegate m_newPixMap;
    NewImageDelegate m_newImage;
};

#endif // IMAGESOURCE_H

图像源.cpp

#include "imagesource.h"

#include <QPixmap>
#include <QPainter>

#include <thread>

ImageSource::ImageSource()
{
}

boost::signals2::connection ImageSource::subscribeNewImage(NewImageDelegate::slot_function_type f)
{
    return m_newImage.connect(f);
}

void ImageSource::generateImages()
{
    std::thread t([this]() {
        auto image = QImage("/home/junaid/testing_ground/fourthtime/images.jpeg");
        m_newImage(image);

        /// useless wait. just simulating that another image comes after sometime and so on onwards.
        int random_wait = 2; //sec
        sleep(random_wait);

        image = QImage("/home/junaid/Downloads/pnggrad16rgb.png");
        m_newImage(image);
    });
    t.detach();
}

boost::signals2::connection ImageSource::subscribeNewPixMap(NewPixMapDelegate::slot_function_type f)
{
    return m_newPixMap.connect(f);
}

void ImageSource::generatePixmaps(const QString &id, QSize *size, const QSize &requestedSize)
{
    int width = 100;
    int height = 50;

    if (size) {
        *size = QSize(width, height);
    }
    QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
                   requestedSize.height() > 0 ? requestedSize.height() : height);
    pixmap.fill(QColor(id).rgba());

    // write the color name
    QPainter painter(&pixmap);
    QFont f = painter.font();
    f.setPixelSize(20);
    painter.setFont(f);
    painter.setPen(Qt::black);
    if (requestedSize.isValid())
        painter.scale(requestedSize.width() / width, requestedSize.height() / height);
    painter.drawText(QRectF(0, 0, width, height), Qt::AlignCenter, id);

    m_newPixMap(pixmap);
}

这是 CMake 文件:

cmake_minimum_required(VERSION 2.8.12)

project(non_existent_property LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5 COMPONENTS Core Quick REQUIRED)

file( GLOB SRCS *.cpp *.h )

add_executable(${PROJECT_NAME} "qml.qrc" ${SRCS})

target_link_libraries(${PROJECT_NAME} Qt5::Core Qt5::Quick "pthread")
4

1 回答 1

0

所以,这里是工作 main.cpp 的样子。我被我创建的 QmlContext 误导了,在@GrecKo 和 jpnurmi 的评论的帮助下,我明白我必须为根上下文设置属性。

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "imageprovidervm.h"
#include "imagesource.h"

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

    QQmlApplicationEngine engine;
    // QQmlContext *context = new QQmlContext(engine.rootContext());

    auto model = std::make_shared<ImageSource>();

    auto vm = new ImageProviderVM(model);
    engine.addImageProvider(QLatin1String("imageProvider"), vm);
    engine.rootContext()->setContextProperty("imageProvide", vm );

    model->generateImages();

    engine.load(QUrl(QStringLiteral("qrc:/view.qml")));

    return app.exec();
}
于 2018-12-24T15:54:52.873 回答