I am working on a QtQuick 2 application (Qt version 6.2.3). I created one C class (let's call this class "Example") that contains the data that my application should deal with. This class can be instantiated several times, representing different datasets to be displayed.
class ExampleObject : public QObject {
Q_OBJECT
Q_PROPERTY(QString property1 MEMBER property1 CONSTANT)
...
public:
QString property1;
};
Q_DECLARE_METATYPE(ExampleObject*)
I want to be able to display instances of this class via QML, therefore I created a "Example" custom component with a property pointing to the Example C object containing the data I want to display.
ExampleComponent {
property var exampleCppObject // exampleCppObject is a pointer to an instance of ExampleObject
Label {
text: exampleCppObject.property1
}
}
To be able to change the Example instance used by the QML component, I created functions to "reinitialize" and "update" the component:
ExampleComponent {
property var exampleCppObject // exampleCppObject is a pointer to an instance of ExampleObject
property string textToDisplay
function update() {
textToDisplay=Qt.binding(() => exampleCppObject.property1);
}
function reinitialize() {
textToDisplay=""
}
Label {
text: textToDisplay
}
}
I call these functions after changing or deleting the Example object pointed by ExampleCppObject, and this works quite fine. But I feel like this isn't best practice, and it seems to me that I am doing things wrong.
What are better ways of connecting C to QML, in the situation I described?
Edit: my main.cpp essentially consists in:
MainModel mainModel;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("mainModel", &mainModel);
engine.load(QStringLiteral("qrc:/main.qml"));
Where mainModel is an object which can create different instances of ExampleObject while the application is running.
CodePudding user response:
You can optimize the binding textToDisplay
such that you don't have to call the upate
and reinitialize
functions, which seems to be the question you are after:
property var exampleCppObject
property string textToDisplay : exampleCppObject ? exampleCppObject.property1 : ""
In case you need more complex logic in the future, you can also use braces:
property string textToDisplay: {
console.log("log me everytime the binding is reevalutated")
if(condition1)
return "invalid"
else if(condition2)
return exampleCppObject.property2
else
return exampleCppObject.property1
}
The best part of this, is that QQmlEngine actually reevaluates the binding for every property that is used in this binding (which has a notify signal), so if crafted correctly, you can largely leave the binding alone (meaning you don't need the update
and reinitialize
function)
CodePudding user response:
For connecting c class in QML : This is one example :
- First you have one c class, you should use
Q_PROPERTY
if you want to use class objects in qmlREAD
andWRITE
is for its get and set function andNOTIFY
for class signals. If you write one function and you want to use it in QML you should useQ_INVOKABLE
.
This is my c class and I want to use it in QML :
#ifndef TEST_H
#define TEST_H
#include <QObject>
class Test: public QObject
{
Q_OBJECT
Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged)
public:
explicit Test(QObject *parent = nullptr);
const QString & userName() const;
void setUserName(const QString &newUserName);
Q_INVOKABLE void myFunc();
signals:
void userNameChanged();
private:
QString m_userName;
};
#endif // TEST_H
The important part is that in main.cpp
you use qmlRegisterType
I didn't see that you do this in your code and your problem maybe because of this.
in main.cpp:
#include <QApplication>
#include <QQmlApplicationEngine>
#include "test.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QApplication app(argc, argv);
qmlRegisterType<Test>("Test", 1, 0, "Test");
QQmlApplicationEngine engine;
auto root_context = engine.rootContext();
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
{
return -1;
}
return app.exec();
}
and in main.qml
:
import QtQuick 2.15
import QtQuick.Window 2.15
import Test 1.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
Test{
id:tst
userName: "Parisa"
}
}
I import Test 1.0
and create one Test
object and I have access to all its members and functions and signals.