Using a C++ class variable in QML file - c++

How can I use a C++ class variable in QML file in Qt. I want to set a variable based on Q_OS_Android in c++ file and evaluate a condition in QML file. How will this be possible?

You have to declare the variable as property in your header file and register the class with qml in your main. Here is an example for a class Foo and a variable QString var:
class Foo : ...
{
Q_OBJECT
Q_PROPERTY(QString var READ getVar WRITE setVar NOTIFY varChanged)
public:
Foo();
~Foo();
QString getVar() const {return m_var;}
void setVar(const QString &var);
signals:
void varChanged();
public slots:
//slots can be called from QML
private:
QString m_var;
};
In the main you will have something like this:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Foo>("MyApp", 1, 0, "Foo");
QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
In your Qml File you can simply import your class using:
import MyApp 1.0
And then use your class as you would any normal QML Type:
Foo{
id: myClass
var: "my c++ var"
...
}

Related

Accessing instances of a class from qml context

I am new both QT and QML. I have a class, which instantiates subclasses. I would like to expose the methods within these subclasses to my UI with some qml binding.
For example
class MainClass: QObject
{
Q_OBJECT
Subclass subclass;
MainClass();
}
class Subclass:QObject
{
Q_Object
Subclass();
public slots:
void someMethod();
}
Main.C
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QQuickView *view = new QQuickView;
MainClass mainclass;
view->rootContext()->setContextProperty("MainClass", &mainClass);
view->setSource(QUrl("qrc:/main.qml"));
view->show();
}
In this case I would like to access mainclass.subclass.someMethod() from within the QML UI.
Is there a good way to do this? Should I provide wrapper methods in MainClass for each function/property I would like to access.
It is possible by making SubClass a property of MainClass. For example:
class MainClass : public QObject
{
Q_OBJECT
Q_PROPERTY(SubClass *subClass MEMBER subClass CONSTANT)
public:
MainClass();
private:
SubClass *subclass;
};
These are called "grouped properties" in QML.

How to pass enum class to QML?

I am on learning to QML with Qt and get some trouble with passing enum class to qml.
When I use signal with int parameters - it's all right and code work perfectly.
But, and here the trouble, if I use signal with some enum class parameters I have undefined values in qml signal handler. I tried to register enum class through qmlRegisterType but it's not working. I will be grateful for the help.
Here the code:
Some Helper class
class Helper : public QObject
{
Q_OBJECT
Q_ENUMS(Requester)
Q_ENUMS(JANSWER)
public:
enum class Requester {
ReqLogin,
ReqNull,
ReqSave,
ReqError,
ReqUnknown
};
enum class JANSWER {
OK,
Complete,
Error,
Unknown
};
};
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<JsonPackWorker>("com.jsonpackworker", 1, 0, "JsonPackWorker");
qmlRegisterType<Helper>("com.Helper", 1, 0, "Helper");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
JsonPackWorker.h
class JsonPackWorker : public QObject
{
Q_OBJECT
public:
<...>
signals:
<...>
void sendAnswer(Helper::Requester req, Helper::JANSWER answer);
public slots:
<...>
};
Somewehere in JsonPackWorker.cpp
emit sendAnswer(Helper::Requester::ReqNull, Helper::JANSWER::OK);
main.qml
<...>
import com.jsonpackworker 1.0
import com.Helper 1.0
ApplicationWindow {
id: mainWindow
// Requests in answers
property int reqLogin: Helper.ReqLogin
<...>
JsonPackWorker {
id: packWorker
<...>
onSendAnswer: {
// Here I've got undefined undefined if there enum class parameters
console.log(req + " " + answer)
switch(req) {
case reqLogin: loginDial.checkLogin(answer)
break;
default:
}
}
}
}
The problem was in Helper class (thanks to Qt community).
class Helper {
...
};
Q_DECLARE_METATYPE(Helper::Requester)
Q_DECLARE_METATYPE(Helper::JANSWER)

Add ListView sections based on c++ QStringList model

The QStringList I'am providing to my QML ListView is displayed correctly. Now I want to reorganize the strings into sections but I'am kind of stuck on what to provide to the section.property ! Is there a minimal change I can make to my code to provide this info ?
Here is my code so far:
C++ Class:
class Foo : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringList data READ getData WRITE setData NOTIFY dataChanged)
public:
QStringList getData() const {return m_data;}
void setData(const QStringList &data);
signals:
void dataChanged();
private:
QStringList m_data;
};
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
qmlRegisterType<Foo>("MyModule", 1, 0, "Foo");
QQuickView view;
view.setSource(QUrl("qrc:/main.qml"));
view.show();
return app.exec();
}
main.qml
import MyModule 1.0
Foo{
id: foo
}
...
ListView {
id: myView
model: foo.data
delegate: Text {text: modelData}
section {
property: what should I write in here ?
}
}

Best way to have qml function and c++ slot and vice versa for the same item

I want to do something like this
QML app:
{
signal qmlSignal
function qmlFunction
}
And
c++ Hnadler:
{
c++ slot
c++ signal
}
Want to have two way communication with the same qml object.
I am referring http://qt-project.org/doc/qt-4.8/qtbinding.html
for changing a value in qml from C++, we can do
QDeclarativeEngine engine;
QDeclarativeComponent component(&engine, "MyItem.qml");
QObject *object = component.create();
QVariant returnedValue;
QVariant msg = "Hello from C++";
QMetaObject::invokeMethod(object, "myQmlFunction",
Q_RETURN_ARG(QVariant, returnedValue),
Q_ARG(QVariant, msg));
qDebug() << "QML function returned:" << returnedValue.toString();
delete object;
can be used to call qml function. But with this we cannot use QT method
And
class MyClass : public QObject
{
Q_OBJECT
public slots:
void cppSlot(const QString &msg) {
qDebug() << "Called the C++ slot with message:" << msg;
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QDeclarativeView view(QUrl::fromLocalFile("MyItem.qml"));
QObject *item = view.rootObject();
MyClass myClass;
QObject::connect(item, SIGNAL(qmlSignal(QString)),
&myClass, SLOT(cppSlot(QString)));
view.show();
return app.exec();
}
This can be used for qmlsignal and c++ slot.
Is there a way both of these can be done in one object?
=== Updated question ===
You can call slots or Q_INVOKABLE methods just fine in QML to change "C++ properties" from QML. You will need to expose the C++ object as a context property though. You would need to write something like this below:
myclass.h
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass(QObject *parent) : QObject(parent) { ... }
Q_INVOKABLE void myInvokable();
public slots:
void mySlot();
...
}
main.cpp
...
MyClass myClassObject;
QQuickView view;
view.rootContext()->setContextProperty("myClassContextProperty", &myClassObject;
view->setSource(QUrl::fromLocalFile("main.qml"));
view->show();
...
main.qml
Button {
...
// You can replace onClicked with your own custom signal
onClicked: myClassContextProperty.myslot()
// or
onClicked: myClassContextProperty.myInvokable()
...
}
=== Further questions in the comment ===
You would have a Q_PROPERTY in C++, and you bind that property to your property in QML, or catch the onFooChanged signal handler for the property called "foo".
myclass.h
class MyClass : public QObject
{
Q_OBJECT
Q_PROPERTY(foo READ foo NOTIFY fooChanged)
public:
MyClass(QObject *parent) : QObject(parent) { ... }
int foo() const;
public signals:
void fooChanged();
public slots:
void mySlot() { foo = 5; emit fooChanged(); };
private:
int foo;
...
}
main.cpp
...
MyClass myClassObject;
QQuickView view;
view.rootContext()->setContextProperty("myClassContextProperty", &myClassObject;
view->setSource(QUrl::fromLocalFile("main.qml"));
view->show();
...
main.qml
...
// Bind foo to bar
property int bar: myClassContextProperty.foo
=== Original question ===
It seems that you are trying to ask if you can declare the same both in C++ and QML simultaneously, i.e. some parts of it in QML and then the rest in QML.
I think you would need to register (qmlRegisterMetaType, etc) your C++ type with the Qt meta type system, and then you could use that class as an item in QML (maybe with a parent?) to achieve what you wish.
This is the relevant documentation for further reading:
Registering an Instantiable Object Type
For your convenience, here goes some code inline:
message.h
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
// ...
};
qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
...
main.qml
import com.mycompany.messaging 1.0
Message {
author: "Amelie"
creationDate: new Date()
}

QML callback from C++ with custom type as parameter

I would like to be able to call a QML function from C++ with an instance of a custom class as a parameter and then manipulate the instance from QML.
Here is what I did so far :
Data.h
class Data : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
public :
Data() : QObject(), _text("Foo") { }
virtual ~Data() { }
Data(const Data & other) { _text = other._text; }
QString text() const { return _text; }
void setText(const QString & text) { _text = text; }
private :
QString _text;
};
Q_DECLARE_METATYPE(Data);
Main.cpp
#include "Data.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Data callBackData;
QQmlEngine engine;
QQmlComponent rootComponent(&engine, QUrl::fromLocalFile("CallBack.qml"));
QObject * rootObj = rootComponent.create();
QMetaObject::invokeMethod(rootObj, "callMeBack",
Q_ARG(QVariant, QVariant::fromValue(callBackData)));
return app.exec();
}
CallBack.qml
import QtQuick 2.0
Item {
function callMeBack(data) {
console.log(data.text)
}
}
The console outputs "Undefined". Did I do something wrong ?
When changing the function body to console.log(data) it outputs "QVariant(Data)" so why can't I access the text property of data ?
I tried registering Data as a QML type using qmlRegisterType<Data>(); but this does not change anything.
Try pass a QObject pointer instead:
Data *callbackData = new Data;
...
QMetaObject::invokeMethod(rootObj, "callMeBack",
Q_ARG(QVariant, QVariant::fromValue(callBackData)));
Not tested, but should work (QML recognize QObject* type).