Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

qt

qml

qtquick2

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?

like image 999
neeru Avatar asked Mar 22 '23 01:03

neeru


1 Answers

=== 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()
}
like image 93
lpapp Avatar answered Apr 26 '23 10:04

lpapp