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