Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
interactqmlfromcpp.qdoc
Go to the documentation of this file.
1
// Copyright (C) 2017 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
3
/*!
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.
7
8
All QML object types are QObject-derived types, whether they are internally
9
implemented by the engine or \l
10
{qtqml-cppintegration-definetypes.html}{defined by third-party
11
sources}. This means the QML engine can use the Qt \l{Meta Object System} to
12
dynamically instantiate any QML object type and inspect the created objects.
13
14
This is useful for creating QML objects from C++ code, whether to display a QML
15
object that can be visually rendered, or to integrate non-visual QML object data
16
into a C++ application. Once a QML object is created, it can be inspected from
17
C++ in order to read and write to properties, invoke methods and receive signal
18
notifications.
19
20
For more information about C++ and the different QML integration methods,
21
see the
22
\l {Overview - QML and C++ Integration} {C++ and QML integration overview} page.
23
24
\section1 Loading QML Objects from C++
25
26
A QML document can be loaded with QQmlComponent or QQuickView. QQmlComponent
27
loads a QML document as a C++ object that can then be modified from C++ code.
28
QQuickView also does this, but as QQuickView is a QWindow-derived class, the
29
loaded object will also be rendered into a visual display; QQuickView is
30
generally used to integrate a displayable QML object into an application's
31
user interface.
32
33
For example, suppose there is a \c MyItem.qml file that looks like this:
34
35
\snippet qml/qtbinding/loading/MyItem.qml start
36
\snippet qml/qtbinding/loading/MyItem.qml end
37
38
This QML document can be loaded with QQmlComponent or QQuickView with the
39
following
40
C++ code. Using a QQmlComponent requires calling QQmlComponent::create() to
41
create
42
a new instance of the component, while a QQuickView automatically creates an
43
instance of the
44
component, which is accessible via QQuickView::rootObject():
45
46
\table
47
\row
48
\li
49
\snippet qml/qtbinding/loading/main.cpp QQmlComponent-a
50
\dots 0
51
\snippet qml/qtbinding/loading/main.cpp QQmlComponent-b
52
\li
53
\snippet qml/qtbinding/loading/main.cpp QQuickView-includes
54
\dots 0
55
\snippet qml/qtbinding/loading/main.cpp QQuickView
56
\endtable
57
58
This \c object is the instance of the \c MyItem.qml component that has been
59
created. You can now modify the item's properties using
60
\l QObject::setProperty() or \l QQmlProperty::write():
61
62
\snippet qml/qtbinding/loading/main.cpp properties
63
64
The difference between \c QObject::setProperty() and \c QQmlProperty::write()
65
is that the latter will also remove the binding in addition to setting the
66
property value. For example, suppose the \c width assignment above had been a
67
binding to \c height:
68
69
\code
70
width: height
71
\endcode
72
73
If the \c height of the \c Item changed after the
74
\c {object->setProperty("width", 500)} call, the \c width would be updated
75
again, as the binding remains active. However, if the \c height changes after the
76
\c {QQmlProperty(object, "width").write(500)} call, the \c width will not be
77
changed, as the binding does not exist anymore.
78
79
Alternatively, you can cast the object to its actual type and call methods with
80
compile-time safety. In this case the base object of \c MyItem.qml is an
81
\l Item, which is defined by the QQuickItem class:
82
83
\snippet qml/qtbinding/loading/main.cpp cast
84
85
You can also connect to any signals or call methods defined in the component
86
using QMetaObject::invokeMethod() and QObject::connect(). See \l {Invoking QML Methods}
87
and \l {Connecting to QML Signals} below for further details.
88
89
\section1 Accessing QML Objects via well-defined C++ Interfaces
90
91
The best way of interacting with QML from C++ is to define an interface for
92
doing so in C++ and accessing it in QML itself. With other methods, refactoring
93
your QML code can easily lead to your QML / C++ interaction breaking. It also
94
helps to reason about the interaction of QML and C++ code, as having it driven
95
via QML can be more easily reasoned about by both users and tooling such as
96
qmllint. Accessing QML from C++ will lead to QML code that cannot be understood
97
without manually verifying that no outside C++ code is modifying a given QML
98
component, and even then the extent of the access might change over time, making
99
continued use of this strategy a maintenance burden.
100
101
To let QML drive the interaction, first you need to define a C++ interface:
102
103
\code
104
class CppInterface : public QObject
105
{
106
Q_OBJECT
107
QML_ELEMENT
108
// ...
109
};
110
\endcode
111
112
Using a QML-driven approach, this interface can be interacted with in two ways:
113
114
\section2 Singletons
115
116
One option is to register the interface as a singleton by adding the \l
117
QML_SINGLETON macro to the interface, exposing it to all components. Following
118
that, the interface becomes available via a simple import statement:
119
120
\qml
121
import my.company.module
122
123
Item {
124
Component.onCompleted: {
125
CppInterface.foo();
126
}
127
}
128
\endqml
129
130
Use this approach if you need your interface in more places than the root component, as
131
simply passing down an object would require explicitly passing it on to other
132
components via a property or utilizing the slow and not recommended method of
133
using \l {Unqualified access}{unqualified access}.
134
135
\section2 Initial properties
136
137
Another option is to mark the interface as uncreatable via \l QML_UNCREATABLE
138
and supplying it to the root QML Component by using \l
139
QQmlComponent::createWithInitialProperties() and a \l {Required
140
Properties}{required property} on the QML end.
141
142
Your root component may look something like this:
143
144
\qml
145
import QtQuick
146
147
Item {
148
required property CppInterface interface
149
Component.onCompleted: {
150
interface.foo();
151
}
152
}
153
\endqml
154
155
Marking the property as required here protects the component against being
156
created without the interface property being set.
157
158
You can then initialize your component in the same way as outlined in \l
159
{Loading QML Objects from C++} except using \c {createWithInitialProperties()}:
160
161
\code
162
component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});
163
\endcode
164
165
This method is to be preferred if you know that your interface only needs to be
166
available to the root component. It also allows for connecting to signals and
167
slots of the interface more easily on the C++ side.
168
169
If neither of these methods suit your needs you may want to investigate the usage of
170
\l {Using C++ Models with Qt Quick Views}{C++ models} instead.
171
172
\section1 Accessing Loaded QML Objects by Object Name
173
174
QML components are essentially object trees with children that have siblings and
175
their own children. Child objects of QML components can be located using the
176
QObject::objectName property with QObject::findChild(). For example, if the root
177
item in \c MyItem.qml had a child \l Rectangle item:
178
179
\snippet qml/qtbinding/loading/MyItem.qml start
180
\codeline
181
\snippet qml/qtbinding/loading/MyItem.qml child
182
\snippet qml/qtbinding/loading/MyItem.qml end
183
184
The child could be located like this:
185
186
\snippet qml/qtbinding/loading/main.cpp findChild
187
188
Note that an object may have multiple children with the same \c objectName.
189
For example, \l ListView creates multiple instances of its delegate, so if its
190
delegate is declared with a particular objectName, the \l ListView will have
191
multiple children with the same \c objectName. In this case,
192
QObject::findChildren() can be used to find all children with a matching
193
\c objectName.
194
195
\include warning.qdocinc
196
197
\section1 Accessing Members of a QML Object Type from C++
198
199
\section2 Properties
200
201
Any properties declared in a QML object are automatically accessible from C++.
202
Given a QML item like this:
203
204
\snippet qml/qtbinding/properties-qml/MyItem.qml 0
205
206
The value of the \c someNumber property can be set and read using QQmlProperty,
207
or QObject::setProperty() and QObject::property():
208
209
\snippet qml/qtbinding/properties-qml/main.cpp 0
210
211
You should always use QObject::setProperty(), QQmlProperty or
212
QMetaProperty::write() to change a QML property value, to ensure the QML
213
engine is made aware of the property change. For example, say you have a
214
custom type \c PushButton with a \c buttonText property that internally
215
reflects the value of a \c m_buttonText member variable. Modifying the member
216
variable directly like this is not a good idea:
217
218
\code
219
//bad code
220
QQmlComponent component(engine, "MyButton.qml");
221
PushButton *button = qobject_cast<PushButton*>(component.create());
222
button->m_buttonText = "Click me";
223
\endcode
224
225
Since the value is changed directly, this bypasses Qt's \l{The Meta-Object
226
System}{meta-object system} and the QML engine is not made aware of the
227
property change. This means property bindings to \c buttonText would not be
228
updated, and any \c onButtonTextChanged handlers would not be called.
229
230
\section2 Invoking QML Methods
231
232
All QML methods are exposed to the meta-object system and can be called from
233
C++ using QMetaObject::invokeMethod(). You can specify types for the parameters
234
and the return value after the colon character, as shown in the code snippet
235
below. This can be useful, for example, when you want to connect a signal in
236
C++ with a certain signature to a QML-defined method. If you omit the types,
237
the C++ signature will use QVariant.
238
239
Here is a C++ application that calls a QML method using
240
QMetaObject::invokeMethod():
241
242
\table
243
\row
244
\li QML
245
\li \snippet qml/qtbinding/functions-qml/MyItem.qml 0
246
\row
247
\li C++
248
\li \snippet qml/qtbinding/functions-qml/main.cpp 0
249
\endtable
250
251
Notice the parameter and return type specified after the colon. You can use \l
252
{QML Value Types}{value types} and \l {QML Object Types}{object types} as type
253
names.
254
255
If the type is omitted or specified as \c var in QML, then you must pass
256
QVariant as type with Q_RETURN_ARG() and Q_ARG() when calling
257
QMetaObject::invokeMethod.
258
259
\section2 Connecting to QML Signals
260
261
All QML signals are automatically available to C++, and can be connected to
262
using QObject::connect() like any ordinary Qt C++ signal. In return, any C++
263
signal can be received by a QML object using
264
\l {qtqml-syntax-signals.html}{signal handlers}.
265
266
Here is a QML component with a signal named \c qmlSignal that is emitted with
267
a string-type parameter. This signal is connected to a C++ object's slot using
268
QObject::connect(), so that the \c cppSlot() method is called whenever the
269
\c qmlSignal is emitted:
270
271
\table
272
\row
273
\li
274
\snippet qml/qtbinding/signals-qml/MyItem.qml 0
275
\row
276
\li
277
\snippet qml/qtbinding/signals-qml/myclass.h 0
278
\codeline
279
\snippet qml/qtbinding/signals-qml/main.cpp 0
280
\endtable
281
282
A QML object type in a signal parameter is translated to a pointer to the class
283
in C++:
284
285
\table
286
\row
287
\li
288
289
\qml
290
// MyItem.qml
291
import QtQuick 2.0
292
293
Item {
294
id: item
295
width: 100; height: 100
296
297
signal qmlSignal(anObject: Item)
298
299
MouseArea {
300
anchors.fill: parent
301
onClicked: item.qmlSignal(item)
302
}
303
}
304
\endqml
305
306
\li
307
\code
308
class MyClass : public QObject
309
{
310
Q_OBJECT
311
public slots:
312
void cppSlot(QQuickItem *item) {
313
qDebug() << "Called the C++ slot with item:" << item;
314
315
qDebug() << "Item dimensions:" << item->width()
316
<< item->height();
317
}
318
};
319
320
int main(int argc, char *argv[]) {
321
QGuiApplication app(argc, argv);
322
323
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));
324
QObject *item = view.rootObject();
325
326
MyClass myClass;
327
QObject::connect(item, SIGNAL(qmlSignal(QVariant)),
328
&myClass, SLOT(cppSlot(QVariant)));
329
330
view.show();
331
return app.exec();
332
}
333
\endcode
334
\endtable
335
336
*/
qtdeclarative
src
qml
doc
src
cppintegration
interactqmlfromcpp.qdoc
Generated on
for Qt by
1.16.1