在 QML 中访问 C++ 结构的最佳方式
Best way to access a cpp structure in QML
我需要在 cpp 和 QML 之间传递结构。如果我使用 属性 我应该创建一个单独的 set 和 get 函数,我的结构至少包含 5 个成员,所以我觉得对所有这些成员使用 set 和 get 并不好。
以下是我正在尝试做的一个例子:
MyClass.h
#include <QObject>
#include <QDebug>
using namespace std;
struct MyStruct {
Q_GADGET
int m_val;
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
class MyClass:public QObject
{
Q_OBJECT
Q_PROPERTY(MyStruct mystr READ getMyStruct
WRITE setMyStruct NOTIFY myStructChanged)
public:
explicit MyClass(QObject *parent = nullptr);
MyStruct strObj;
// Edit: changed get function
MyStruct getMyStruct() const
{
return strObj;
}
// Edit: Added set function
void setMyStruct(myStruct val)
{
mystr = val;
emit myStructChanged();
}
signals:
void myStructChanged();
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QObject>
#include "MyClass.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyClass classObj;
engine.rootContext()->setContextProperty("classObj",&classObj);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
Main.qml
import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Window 2.3
ApplicationWindow {
id: applicationWindow
visible: true
width: 600
height: 400
title: qsTr("My App")
MainForm{
id : mainform
Component.onCompleted: {
console.log("name===="+classObj.mystr.name1)
//EDIT added more code to explain the use case.
classObj.myStr.name1 = "abc" //Calls setter
classObj.mystr.name2 = "ans" // Calls setter
}
}
}
如果我只打印 (classObj.myVariant)
我得到 QVariant(MyStruct) 但是当我尝试访问任何参数时 classObj.myVariant.name1
我得到“undefined" 以及如何从 QML 设置变体?
[更新] - 还应将 MyStruct 添加到 Q_DECLARE_METATYPE,如下所示:Q_DECLARE_METATYPE(MyStruct)
您需要元数据才能从 QML 访问 C++ 对象。
对于非 QObject
派生,这是通过使用 Q_GADGET
宏并将成员公开为属性来实现的:
struct MyStruct {
Q_GADGET
int m_val;
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
- 您的结构或简单 class 必须至少有
Q_GADGET
- 您应该声明属性以便从 qml 访问
- 您必须通过
Q_DECLARE_METATYPE()
声明您的 struct/class
- 你必须在某个地方使用
qRegisterMetaType<>()
注册它,然后才能通过引擎加载qml文件,例如main.cpp
所以你会有这样的东西:
//review carefully
struct MyStruct {
Q_GADGET //<-- 1.
Q_PROPERTY(QString str1 MEMBER m_str1) //<-- 2.
public: //<-- important
QString m_str1;
};
Q_DECLARE_METATYPE(MyStruct) //<-- 3.
并在某处使用:
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
Q_INVOKABLE MyStruct setNewConfig(QString v); //<-- e.g.
//...
}
main.cpp
//...
qmlRegisterType<Controller>("AppKernel", 1, 0, "Controller");
qRegisterMetaType<MyStruct>(); //<-- 4.
//...
engine.load(url);
//...
所以在qml中是可用的
main.qml
//...
Controller {
id: con
}
FileDialog {
id: fileDialog
nameFilters: ["Config file (*)"]
onAccepted: {
var a = con.setNewConfig(file);
console.log(a.str1); //<-- yeah! it is here
}
}
//...
NOTE 1: 注意,Qt meta
不支持嵌套classes/struct
注意 2: 您可以像 class
一样公开 struct
。从 QObject
继承并使用 Q_OBJECT
。参见 this article from Evgenij Legotskoj
注意 3: 上面的说明使 struct/class 为 qml 所知,您可以访问 properties/members,但是在 qml 中不可实例化。参见 Qt document
注意 4: 请注意,qmlRegisterType<>()
方法在 Qt 5.15+ 中被标记为“过时”。让自己保持更新 ;)
我需要在 cpp 和 QML 之间传递结构。如果我使用 属性 我应该创建一个单独的 set 和 get 函数,我的结构至少包含 5 个成员,所以我觉得对所有这些成员使用 set 和 get 并不好。 以下是我正在尝试做的一个例子:
MyClass.h
#include <QObject>
#include <QDebug>
using namespace std;
struct MyStruct {
Q_GADGET
int m_val;
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
class MyClass:public QObject
{
Q_OBJECT
Q_PROPERTY(MyStruct mystr READ getMyStruct
WRITE setMyStruct NOTIFY myStructChanged)
public:
explicit MyClass(QObject *parent = nullptr);
MyStruct strObj;
// Edit: changed get function
MyStruct getMyStruct() const
{
return strObj;
}
// Edit: Added set function
void setMyStruct(myStruct val)
{
mystr = val;
emit myStructChanged();
}
signals:
void myStructChanged();
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QObject>
#include "MyClass.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
MyClass classObj;
engine.rootContext()->setContextProperty("classObj",&classObj);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
Main.qml
import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Window 2.3
ApplicationWindow {
id: applicationWindow
visible: true
width: 600
height: 400
title: qsTr("My App")
MainForm{
id : mainform
Component.onCompleted: {
console.log("name===="+classObj.mystr.name1)
//EDIT added more code to explain the use case.
classObj.myStr.name1 = "abc" //Calls setter
classObj.mystr.name2 = "ans" // Calls setter
}
}
}
如果我只打印 (classObj.myVariant)
我得到 QVariant(MyStruct) 但是当我尝试访问任何参数时 classObj.myVariant.name1
我得到“undefined" 以及如何从 QML 设置变体?
[更新] - 还应将 MyStruct 添加到 Q_DECLARE_METATYPE,如下所示:Q_DECLARE_METATYPE(MyStruct)
您需要元数据才能从 QML 访问 C++ 对象。
对于非 QObject
派生,这是通过使用 Q_GADGET
宏并将成员公开为属性来实现的:
struct MyStruct {
Q_GADGET
int m_val;
QString m_name1;
QString m_name2;
QString m_name3;
QString m_name4;
Q_PROPERTY(int val MEMBER m_val)
Q_PROPERTY(QString name1 MEMBER m_name1)
Q_PROPERTY(QString name2 MEMBER m_name2)
Q_PROPERTY(QString name3 MEMBER m_name3)
Q_PROPERTY(QString name4 MEMBER m_name4)
};
- 您的结构或简单 class 必须至少有
Q_GADGET
- 您应该声明属性以便从 qml 访问
- 您必须通过
Q_DECLARE_METATYPE()
声明您的 struct/class
- 你必须在某个地方使用
qRegisterMetaType<>()
注册它,然后才能通过引擎加载qml文件,例如main.cpp
所以你会有这样的东西:
//review carefully
struct MyStruct {
Q_GADGET //<-- 1.
Q_PROPERTY(QString str1 MEMBER m_str1) //<-- 2.
public: //<-- important
QString m_str1;
};
Q_DECLARE_METATYPE(MyStruct) //<-- 3.
并在某处使用:
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
Q_INVOKABLE MyStruct setNewConfig(QString v); //<-- e.g.
//...
}
main.cpp
//...
qmlRegisterType<Controller>("AppKernel", 1, 0, "Controller");
qRegisterMetaType<MyStruct>(); //<-- 4.
//...
engine.load(url);
//...
所以在qml中是可用的
main.qml
//...
Controller {
id: con
}
FileDialog {
id: fileDialog
nameFilters: ["Config file (*)"]
onAccepted: {
var a = con.setNewConfig(file);
console.log(a.str1); //<-- yeah! it is here
}
}
//...
NOTE 1: 注意,Qt meta
不支持嵌套classes/struct注意 2: 您可以像 class
一样公开 struct
。从 QObject
继承并使用 Q_OBJECT
。参见 this article from Evgenij Legotskoj
注意 3: 上面的说明使 struct/class 为 qml 所知,您可以访问 properties/members,但是在 qml 中不可实例化。参见 Qt document
注意 4: 请注意,qmlRegisterType<>()
方法在 Qt 5.15+ 中被标记为“过时”。让自己保持更新 ;)