0

I have a QML file Dialog.qml which is ApplicationWindow and Tab.qml which is Item. There are TabView in Dialog.qml which tabs is formed from Tab.qml. I want to create Tab.qml in Qt, connect its signals to classes in Qt and add that tab to Dialog. Here is relevant part of code:

//Tab.qml
Item {
    id: tb
    anchors.fill: parent
    //...here is signals and controls like RadioButtons and TextFields
}

//Dialog.qml
ApplicationWindow {
    visible: true
    title: "settings"
    flags: Qt.Dialog
    //...
    function addTabfromCpp(tab){
        frame.addTab("from c++", tab);
    }
    TabView {
        id:frame
        //...
    }
}

I know how to call QML functions from Qt when function parameters are primitive types(via QVariant). But how to call function when its parameter is QQuickWindow or other and it is not possible to create QVariant from it?

0

1 Answer 1

1

You can pass QML object ids as function parameters just fine. In C++ those work as QObject *. Also, besides ids you can use the parent property, or children[indexOfChild]. Note that you don't pass the actual objects, since that would require invoking a copy constructor, and copying is disabled for all QObject derived classes, it is passed by reference, which works in JS with var and in C++ with QObject*. In a similar fashion, you can use QObject* to pass objects to QML. Additionally, you might want to add your custom types to the Qt metatypes with qRegisterMetaType() or Q_DECLARE_METATYPE, which will give you autocomplete for that type in QML.

In order to expose C++ functions in the QML context, you need to make those functions either slots or Q_INVOKABLE of a QObject derived class, instantiate the class and use setContextProperty() to expose it to QML.

Or alternatively, you can register that object to the QML engine so you can instantiate it, you can even share the same data across multiple instances of that object by following this example.

EDIT: OK, try this one:

QML:

ApplicationWindow {
    objectName: "blah"
    //...
    function foo(obj) { console.log(obj) }
}

CPP:

QObject * root = engine.rootObjects().at(0);
QMetaObject::invokeMethod(root, "foo", Q_ARG(QVariant, QVariant::fromValue(root)));

and output is

qml: ApplicationWindow_QMLTYPE_11_QML_12(0x4121e70, "blah")

Seems you have to pass it as a Q_ARG(QVariant, QVariant::fromValue(QObject*)

However, TabView.addTab() expects not an object (which is an instance of a Component) but a component, i.e. a prototype for an object.

One way you can do that is:

QObject * root = engine.rootObjects().at(0);
QQmlComponent comp(&engine, QUrl("qrc:/Test.qml"));
QMetaObject::invokeMethod(root, "addTab", Q_ARG(QVariant, QVariant::fromValue(&comp)));
Sign up to request clarification or add additional context in comments.

3 Comments

here is slot for button. After button is clicked new Tab should be added void MainWindow::buttonClicked(){ QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:///Tab.qml"))); QObject topLevel = engine.rootObjects().value(0); QMetaObject::invokeMethod(window, "addTabfromCpp", Q_ARG(QObject, topLevel));} However it gives an error QMetaObject::invokeMethod: No such method Dialog_QMLTYPE_57::addTabfromCpp(QObject*)
thanks, now it pass QObject* to QML. However the program gives runtime error: ** Cannot assign QObject* to QQmlComponent* ** in QML function addTabfromCpp(tab){ frame.addTab ("from c++", tab);}
In that function I add parameter(Item) to TabView (it was given in the body of the question).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.