json C++和Qt/QML数据交换的问题

t40tm48m  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(127)

为什么在QML代码中会出现这个错误:ReferenceError: m_jsonDocStr is not defined,即使在C++代码中指定了m_jsonDocStr

Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)

为什么不能从QML打开www.example.com()C函数?QmlLink.open() C function is not opened from QML? (neither as a normal member function nor as a slot)

TypeError: Property 'open' of object [object Object] is not a function

接下来,用“<--”注解,我指向代码的关键行,以及我得到的错误消息。
这是QML文件:

/** Main.qml */

import QtCore
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts
import main

ApplicationWindow {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Data input widget")
    
    property string dataFilename: ""
    property string dataFile: ""
    
    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            Action {
                text: qsTr("&Open...")
                onTriggered: fileDialog.open()
            }
        }
    }

    ScrollView {
        id: fileContents
        anchors.fill: parent
        property string dataFile: m_jsonDocStr  // <-- ReferenceError: m_jsonDocStr is not defined
        TextArea {
            text: "File: " + dataFilename + "\n" + dataFile + "\nLength: " + dataFile.length
        }
    }

    FileDialog {
        id: fileDialog
        title: "Open data file"
        nameFilters: ["JSON files (*.json)"]
        onAccepted: {
            dataFilename = selectedFile
            console.log("Open file: " + dataFilename)
            QmlLink.open(dataFilename)      // <-- TypeError: Property 'open' of object [object Object] is not a function
            console.log("File contents: " + m_jsonDocStr)
        }
        onRejected: {
            console.log("No file selected.")
        }
    }
}

下面是头文件:

/** QmlLink.hpp */

#ifndef QMLLINK_HPP
#define QMLLINK_HPP

#include <QObject>
#include <QJsonDocument>
#include <QtQml/qqmlregistration.h>

class QmlLink : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QJsonDocument m_jsonDoc READ jsonDoc WRITE setJsonDoc NOTIFY jsonDocChanged)
    Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)
    QML_ELEMENT

public:
    explicit QmlLink(QObject *parent = nullptr);

public slots:
    QJsonDocument jsonDoc() const { return m_jsonDoc; }
    void          setJsonDoc(const QJsonDocument &jsonDoc) { m_jsonDoc = jsonDoc; }
    QString       jsonDocToStr() const { return m_jsonDoc.toJson(); }
    void          setJsonDocStr(const QString &jsonDoc) { m_jsonDoc = QJsonDocument::fromJson(jsonDoc.toUtf8()); }

signals:
    void jsonDocChanged();
    void jsonDocStrChanged();

public slots:
    void menuOpen();
    int  open(QString filePath);

private:
    QJsonDocument m_jsonDoc;
    QString m_jsonDocStr;

    QString m_jsonFileName = "default.json";
};

#endif // QMLLINK_HPP

这是实现文件:

/** QmlLink.cpp */

#include "QmlLink.hpp"
#include <iostream> 
#include <QDebug>
#include <QFile>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickView>

QmlLink::QmlLink(QObject *parent) : QObject{parent} {}

void QmlLink::menuOpen() {
    open(m_jsonFileName);
}

int QmlLink::open(QString filePath)
{
    m_jsonFileName = filePath;

    QUrl url(filePath);
    QFile jsonFile;
    jsonFile.setFileName(url.toLocalFile());

    if(jsonFile.open(QIODevice::ReadOnly) == false) {
        return -1;
    }

    const QByteArray data = jsonFile.readAll();
    m_jsonDoc = QJsonDocument::fromJson(data);

    const QString strDoc(m_jsonDoc.toJson(QJsonDocument::Compact));

    std::cout << "Data file contents: " << strDoc.toStdString() << std::endl;

    return 0;
}

这是一个经典的main()函数:

/** main.cpp */

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

#include "QmlLink.hpp"

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

    QmlLink qmlLink;

    QQmlApplicationEngine engine;
    const QUrl url(u"qrc:/main/Main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
        &app, []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.load(url);

    QQmlContext *rootContext = engine.rootContext();
    rootContext->setContextProperty("QmlLink", &qmlLink);

    return app.exec();
}

这是一个简单的JSON文件:

{
    "Array": [
        true,
        999,
        "string"
    ],
    "Key": "Value",
    "null": null
}

工具版本:

  • Qt 6.5
  • 操作系统:Linux
  • gcc 13.1
  • clang 15
c2e8gylq

c2e8gylq1#

在加载url之前,您应该设置context属性:

QGuiApplication app(argc, argv);

QmlLink qmlLink;

QQmlApplicationEngine engine;
// set the context property here
QQmlContext *rootContext = engine.rootContext();
rootContext->setContextProperty("QmlLink", &qmlLink);

const QUrl url(u"qrc:/main/Main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
    &app, []() { QCoreApplication::exit(-1); },
    Qt::QueuedConnection);
engine.load(url);

并修复Main.qml

/** Main.qml */

import QtCore
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import QtQuick.Dialogs
import QtQuick.Layouts

ApplicationWindow {
    id: window
    width: 640
    height: 480
    visible: true
    title: qsTr("Data input widget")
    
    property string dataFilename: ""
    
    menuBar: MenuBar {
        Menu {
            title: qsTr("&File")
            Action {
                text: qsTr("&Open...")
                onTriggered: fileDialog.open()
            }
        }
    }

    ScrollView {
        id: fileContents
        anchors.fill: parent
        property string dataFile: QmlLink.m_jsonDocStr // add context property
        TextArea {
            // add id of the ScrollView to access dataFile
            text: "File: " + dataFilename + "\n" + fileContents.dataFile + "\nLength: " + fileContents.dataFile.length
        } 
    }

    FileDialog {
        id: fileDialog
        title: "Open data file"
        nameFilters: ["JSON files (*.json)"]
        onAccepted: {
            dataFilename = selectedFile
            console.log("Open file: " + dataFilename)
            QmlLink.open(dataFilename)
            // add context property 
            console.log("File contents: " + QmlLink.m_jsonDocStr)
        }
        onRejected: {
            console.log("No file selected.")
        }
    }
}

要在ScrollView中显示文件的内容,QmlLink.cpp中还需要做一些改动:

int QmlLink::open(QString filePath)
{
    m_jsonFileName = filePath;

    QUrl url(filePath);
    QFile jsonFile;
    jsonFile.setFileName(url.toLocalFile());

    if(jsonFile.open(QIODevice::ReadOnly) == false) {
        return -1;
    }

    const QByteArray data = jsonFile.readAll();
    m_jsonDoc = QJsonDocument::fromJson(data);

    const QString strDoc(m_jsonDoc.toJson(QJsonDocument::Compact));

    std::cout << "Data file contents: " << strDoc.toStdString() << std::endl;

    emit jsonDocStrChanged(); // update the property for QML

    return 0;
}

QmlLink.hpp

void setJsonDocStr(const QString &jsonDoc) 
{ 
  m_jsonDoc = QJsonDocument::fromJson(jsonDoc.toUtf8());
  emit jsonDocStrChanged(); // update the property for QML
}
f87krz0w

f87krz0w2#

我认为你不能把QJsonDocument从C++传递给QML。正如你提到的,你会得到一个“无法将[undefined]赋值给QString”错误。但是我的想法是通过QByteArray。
下面是我的例子:
在main.cpp中:

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QFileDialog>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>

class FileLoader : public QObject
{
    Q_OBJECT

public:
    explicit FileLoader(QObject *parent = nullptr) : QObject(parent) {}

public slots:
    void openFile()
    {
        QString filePath = QFileDialog::getOpenFileName(nullptr, "Open JSON File", "", "JSON Files (*.json)");

        if (!filePath.isEmpty()) {
            QFile file(filePath);
            if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
                QByteArray data = file.readAll();
                file.close();

                QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
                qDebug() << "JSON File Loaded:" << filePath;
                emit fileLoaded(jsonDoc.toJson(QJsonDocument::Indented));
            }
        }
    }

signals:
    void fileLoaded(const QByteArray &jsonData);
};

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

    QQmlApplicationEngine engine;

    // Create an instance of the FileLoader
    FileLoader fileLoader;

    // Register the FileLoader as a context property
    engine.rootContext()->setContextProperty("fileLoader", &fileLoader);

    // Load the QML file
    const QUrl url(QStringLiteral("qrc:/QmlJson/Main.qml"));
    engine.load(url);

    return app.exec();
}

#include "main.moc"

在Main.qml中

import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    title: "JSON Viewer"

    Text {
        id: jsonDataText
        anchors.centerIn: parent
    }

    Button {
        text: "Open JSON"
        onClicked: fileLoader.openFile()
    }

    Connections {
        target: fileLoader
        function onFileLoaded(jsonData) {
            jsonDataText.text = jsonData
        }
    }
}

这是我的结果:

相关问题