' QML连接:无法分配给不存在的属性'尽管相反的是真的

时间:2017-04-10 12:29:29

标签: c++ qt qml qt-signals qt-slot

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

QML: Using cpp signal in QML always results in "Cannot assign to non-existent property"

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

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

  

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

以下是我的代码(已编辑下来,制作成最低工作示例')。

唯一重要的文件应该是:

  1. 的main.cpp
  2. view.qml
  3. imageprovidervm.cpp
  4. imageprovidervm.h
  5. 我包含了 imagesource 类,只是为了完整,以防有人想要自己编译它。

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

      

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

    有趣的是,intellisense / autocomplete似乎完全正确地检测到了imageProvide。

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

      

    qrc:/view.qml:30:9:QML连接:无法分配给不存在的   property" onNewFrameReceived"

    • 其他信息:在第31行的qml文件中调试并停止断点,显示在"本地和表达式"我只有2个信号的qtcreator,即" objectNameChanged "和" targetChanged "。 为什么???

    的main.cpp

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

    view.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;
    }
    

    imagesource.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
    

    imagesource.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")
    

1 个答案:

答案 0 :(得分: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();
}