英文:
Issues with C++ and Qt/QML data exchange
问题
以下是您要翻译的内容:
QML代码中为什么会出现这个错误:ReferenceError: m_jsonDocStr is not defined
,即使在C++代码中已经定义了m_jsonDocStr
:
Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)
为什么无法从QML中打开C++函数QmlLink.open()?(既不是作为普通成员函数,也不是作为槽函数)
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.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");
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
英文:
Why do I get this error in the QML code: ReferenceError: m_jsonDocStr is not defined
,
even if m_jsonDocStr
is specified here in the C++ code:
Q_PROPERTY(QString m_jsonDocStr READ jsonDocToStr WRITE setJsonDocStr NOTIFY jsonDocStrChanged)
And why the 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
Next, with the "<--" comment I point to the critical lines of the code, with the error messages I get.
This is the QML file:
/** 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.")
}
}
}
Here is the header file:
/** 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
This is the implementation file:
/** 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;
}
This is a classic main() function:
/** 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();
}
This is the trivial JSON file:
{
"Array": [
true,
999,
"string"
],
"Key": "Value",
"null": null
}
Tools versions:
- Qt 6.5
- OS: Linux
- gcc 13.1
- clang 15
答案1
得分: 2
你应该在加载URL之前设置上下文属性:
QGuiApplication app(argc, argv);
QmlLink qmlLink;
QQmlApplicationEngine engine;
// 在这里设置上下文属性
QQmlContext *rootContext = engine.rootContext();
rootContext->setContextProperty("QmlLink", &qmlLink);
const QUrl url("qrc:/main/Main.qml");
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 // 添加上下文属性
TextArea {
// 添加 ScrollView 的 id 以访问 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)
// 添加上下文属性
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(); // 更新用于 QML 的属性
return 0;
}
以及在 QmlLink.hpp
中:
void setJsonDocStr(const QString &jsonDoc)
{
m_jsonDoc = QJsonDocument::fromJson(jsonDoc.toUtf8());
emit jsonDocStrChanged(); // 更新用于 QML 的属性
}
英文:
You should set the context property before loading the url :
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);
and fix the 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.")
}
}
}
To display the content of the file in the ScrollView
, there is also a little change needed in 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;
}
and in QmlLink.hpp
:
void setJsonDocStr(const QString &jsonDoc)
{
m_jsonDoc = QJsonDocument::fromJson(jsonDoc.toUtf8());
emit jsonDocStrChanged(); // update the property for QML
}
答案2
得分: 1
I think you can't pass QJsonDocument
from C++ to QML.
As you mentioned, you will get an "Unable to assign [undefined] to QString" error.
But my idea is to pass QByteArray.
Here is my example:
In 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"
In 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
}
}
}
This is my result:
英文:
I think you can't pass QJsonDocument
from C++ to QML.
As you mentioned you will get an "Unable to assign [undefined] to QString" error.
But My Idea is to pass QByteArray.
Here is my example:
In 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"
in 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
}
}
}
This is my result:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论