1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
4\page qtqml-cppintegration-interactqmlfromcpp.html
5\title Interacting with QML Objects from C++
6\brief Description of how to load and access QML objects from C++ code
8All QML object types are QObject-derived types, whether they are internally
9implemented by the engine or \l
10{qtqml-cppintegration-definetypes.html}{defined by third-party
11sources}. This means the QML engine can use the Qt \l{Meta Object System} to
12dynamically instantiate any QML object type and inspect the created objects.
14This is useful for creating QML objects from C++ code, whether to display a QML
15object that can be visually rendered, or to integrate non-visual QML object data
16into a C++ application. Once a QML object is created, it can be inspected from
17C++ in order to read and write to properties, invoke methods and receive signal
20For more information about C++ and the different QML integration methods,
22\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
24\section1 Loading QML Objects from C++
26A QML document can be loaded with QQmlComponent or QQuickView. QQmlComponent
27loads a QML document as a C++ object that can then be modified from C++ code.
28QQuickView also does this, but as QQuickView is a QWindow-derived class, the
29loaded object will also be rendered into a visual display; QQuickView is
30generally used to integrate a displayable QML object into an application's
33For example, suppose there is a \c MyItem.qml file that looks like this:
35\snippet qml/qtbinding/loading/MyItem.qml start
36\snippet qml/qtbinding/loading/MyItem.qml end
38This QML document can be loaded with QQmlComponent or QQuickView with the
40C++ code. Using a QQmlComponent requires calling QQmlComponent::create() to
42a new instance of the component, while a QQuickView automatically creates an
44component, which is accessible via QQuickView::rootObject():
49\snippet qml/qtbinding/loading/main.cpp QQmlComponent-a
51\snippet qml/qtbinding/loading/main.cpp QQmlComponent-b
53\snippet qml/qtbinding/loading/main.cpp QQuickView
56This \c object is the instance of the \c MyItem.qml component that has been
57created. You can now modify the item's properties using
58\l QObject::setProperty() or \l QQmlProperty::write():
60\snippet qml/qtbinding/loading/main.cpp properties
62The difference between \c QObject::setProperty() and \c QQmlProperty::write()
63is that the latter will also remove the binding in addition to setting the
64property value. For example, suppose the \c width assignment above had been a
71If the \c height of the \c Item changed after the
72\c {object->setProperty("width", 500)} call, the \c width would be updated
73again, as the binding remains active. However, if the \c height changes after the
74\c {QQmlProperty(object, "width").write(500)} call, the \c width will not be
75changed, as the binding does not exist anymore.
77Alternatively, you can cast the object to its actual type and call methods with
78compile-time safety. In this case the base object of \c MyItem.qml is an
79\l Item, which is defined by the QQuickItem class:
81\snippet qml/qtbinding/loading/main.cpp cast
83You can also connect to any signals or call methods defined in the component
84using QMetaObject::invokeMethod() and QObject::connect(). See \l {Invoking QML Methods}
85and \l {Connecting to QML Signals} below for further details.
87\section1 Accessing QML Objects via well-defined C++ Interfaces
89The best way of interacting with QML from C++ is to define an interface for
90doing so in C++ and accessing it in QML itself. With other methods, refactoring
91your QML code can easily lead to your QML / C++ interaction breaking. It also
92helps to reason about the interaction of QML and C++ code, as having it driven
93via QML can be more easily reasoned about by both users and tooling such as
94qmllint. Accessing QML from C++ will lead to QML code that cannot be understood
95without manually verifying that no outside C++ code is modifying a given QML
96component, and even then the extent of the access might change over time, making
97continued use of this strategy a maintenance burden.
99To let QML drive the interaction, first you need to define a C++ interface:
102class CppInterface : public QObject
110Using a QML-driven approach, this interface can be interacted with in two ways:
114One option is to register the interface as a singleton by adding the \l
115QML_SINGLETON macro to the interface, exposing it to all components. Following
116that, the interface becomes available via a simple import statement:
119import my.company.module
122 Component.onCompleted: {
128Use this approach if you need your interface in more places than the root component, as
129simply passing down an object would require explicitly passing it on to other
130components via a property or utilizing the slow and not recommended method of
131using \l {Unqualified access}{unqualified access}.
133\section2 Initial properties
135Another option is to mark the interface as uncreatable via \l QML_UNCREATABLE
136and supplying it to the root QML Component by using \l
137QQmlComponent::createWithInitialProperties() and a \l {Required
138Properties}{required property} on the QML end.
140Your root component may look something like this:
146 required property CppInterface interface
147 Component.onCompleted: {
153Marking the property as required here protects the component against being
154created without the interface property being set.
156You can then initialize your component in the same way as outlined in \l
157{Loading QML Objects from C++} except using \c {createWithInitialProperties()}:
160 component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});
163This method is to be preferred if you know that your interface only needs to be
164available to the root component. It also allows for connecting to signals and
165slots of the interface more easily on the C++ side.
167If neither of these methods suit your needs you may want to investigate the usage of
168\l {Using C++ Models with Qt Quick Views}{C++ models} instead.
170\section1 Accessing Loaded QML Objects by Object Name
172QML components are essentially object trees with children that have siblings and
173their own children. Child objects of QML components can be located using the
174QObject::objectName property with QObject::findChild(). For example, if the root
175item in \c MyItem.qml had a child \l Rectangle item:
177\snippet qml/qtbinding/loading/MyItem.qml start
179\snippet qml/qtbinding/loading/MyItem.qml child
180\snippet qml/qtbinding/loading/MyItem.qml end
182The child could be located like this:
184\snippet qml/qtbinding/loading/main.cpp findChild
186Note that an object may have multiple children with the same \c objectName.
187For example, \l ListView creates multiple instances of its delegate, so if its
188delegate is declared with a particular objectName, the \l ListView will have
189multiple children with the same \c objectName. In this case,
190QObject::findChildren() can be used to find all children with a matching
193\include warning.qdocinc
195\section1 Accessing Members of a QML Object Type from C++
199Any properties declared in a QML object are automatically accessible from C++.
200Given a QML item like this:
202\snippet qml/qtbinding/properties-qml/MyItem.qml 0
204The value of the \c someNumber property can be set and read using QQmlProperty,
205or QObject::setProperty() and QObject::property():
207\snippet qml/qtbinding/properties-qml/main.cpp 0
209You should always use QObject::setProperty(), QQmlProperty or
210QMetaProperty::write() to change a QML property value, to ensure the QML
211engine is made aware of the property change. For example, say you have a
212custom type \c PushButton with a \c buttonText property that internally
213reflects the value of a \c m_buttonText member variable. Modifying the member
214variable directly like this is not a good idea:
218QQmlComponent component(engine, "MyButton.qml");
219PushButton *button = qobject_cast<PushButton*>(component.create());
220button->m_buttonText = "Click me";
223Since the value is changed directly, this bypasses Qt's \l{The Meta-Object
224System}{meta-object system} and the QML engine is not made aware of the
225property change. This means property bindings to \c buttonText would not be
226updated, and any \c onButtonTextChanged handlers would not be called.
228\section2 Invoking QML Methods
230All QML methods are exposed to the meta-object system and can be called from
231C++ using QMetaObject::invokeMethod(). You can specify types for the parameters
232and the return value after the colon character, as shown in the code snippet
233below. This can be useful, for example, when you want to connect a signal in
234C++ with a certain signature to a QML-defined method. If you omit the types,
235the C++ signature will use QVariant.
237Here is a C++ application that calls a QML method using
238QMetaObject::invokeMethod():
243\li \snippet qml/qtbinding/functions-qml/MyItem.qml 0
246\li \snippet qml/qtbinding/functions-qml/main.cpp 0
249Notice the parameter and return type specified after the colon. You can use \l
250{QML Value Types}{value types} and \l {QML Object Types}{object types} as type
253If the type is omitted or specified as \c var in QML, then you must pass
254QVariant as type with Q_RETURN_ARG() and Q_ARG() when calling
255QMetaObject::invokeMethod.
257\section2 Connecting to QML Signals
259All QML signals are automatically available to C++, and can be connected to
260using QObject::connect() like any ordinary Qt C++ signal. In return, any C++
261signal can be received by a QML object using
262\l {qtqml-syntax-signals.html}{signal handlers}.
264Here is a QML component with a signal named \c qmlSignal that is emitted with
265a string-type parameter. This signal is connected to a C++ object's slot using
266QObject::connect(), so that the \c cppSlot() method is called whenever the
267\c qmlSignal is emitted:
272\snippet qml/qtbinding/signals-qml/MyItem.qml 0
275\snippet qml/qtbinding/signals-qml/myclass.h 0
277\snippet qml/qtbinding/signals-qml/main.cpp 0
280A QML object type in a signal parameter is translated to a pointer to the class
293 width: 100; height: 100
295 signal qmlSignal(anObject: Item)
299 onClicked: item.qmlSignal(item)
306 class MyClass : public QObject
310 void cppSlot(QQuickItem *item) {
311 qDebug() << "Called the C++ slot with item:" << item;
313 qDebug() << "Item dimensions:" << item->width()
318 int main(int argc, char *argv[]) {
319 QGuiApplication app(argc, argv);
321 QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
322 QObject *item = view.rootObject();
325 QObject::connect(item, SIGNAL(qmlSignal(QVariant)),
326 &myClass, SLOT(cppSlot(QVariant)));