#qt #qml #qtquick2
#qt #qml #qtquick2 #qt-быстрый #qvariant
Вопрос:
Мне нужно передавать структуры между cpp и QML. Если я использую свойство, я должен создать отдельный набор и получить функции, моя структура содержит минимум 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",amp;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)
Ответ №1:
Вам нужны метаданные для доступа к объектам C из QML.
Для 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)
};
Комментарии:
1. Это сработало!!! если мне нужно заполнить QVariant из QML. Как это сделать. Не могли бы вы привести пример?
2. @pra7 что вы подразумеваете под «заполнением»? Создавать или просто присваивать значения элементам?
3. Да, просто присваивая значения членам, чтобы cpp мог получить доступ к значениям, установленным QML.
4. Ну, просто
yourvar.val = 555
.5. Нет, это невозможно. Если это уже работает, вам не нужно ничего дополнительно делать. Если вы хотите сохранить повторение, просто напишите функцию, которая устанавливает все, что принимает целевой объект и 5 значений свойств.
Ответ №2:
- ваша структура или простой класс должны иметь
Q_GADGET
как минимум - вы должны объявить свойства, чтобы получить доступ из qml
- вы должны объявить свою структуру / класс с помощью
Q_DECLARE_METATYPE()
- вы должны зарегистрировать его с помощью
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
}
}
//...
ПРИМЕЧАНИЕ 1: будьте осторожны, кажется, что вложенные классы / структуры не поддерживаются Qt meta
ПРИМЕЧАНИЕ 2: вы можете отображать struct
точно так же, как class
. Наследовать QObject
и использовать Q_OBJECT
. Смотрите эту статью от Евгения Леготского
ПРИМЕЧАНИЕ 3: Приведенные выше инструкции делают структуру / класс известными qml, и вы можете получить доступ к свойствам / элементам, но не могут быть созданы в qml. см. Документ Qt
ПРИМЕЧАНИЕ 4: Имейте в виду, что qmlRegisterType<>()
этот метод помечен как «устаревший» в Qt 5.15 . Держите себя в курсе 😉