Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qquickview.cpp
Go to the documentation of this file.
1
// Copyright (C) 2016 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qquickview.h"
6
#
include
"qquickview_p.h"
7
8
#
include
"qquickwindow_p.h"
9
#
include
"qquickitem_p.h"
10
#
include
"qquickitemchangelistener_p.h"
11
12
#
include
<
QtQml
/
qqmlengine
.
h
>
13
#
include
<
QtQml
/
qqmlcomponent
.
h
>
14
#
include
<
private
/
qqmlengine_p
.
h
>
15
#
include
<
private
/
qv4qobjectwrapper_p
.
h
>
16
#
include
<
QtCore
/
qbasictimer
.
h
>
17
18
#
include
<
memory
>
19
20
QT_BEGIN_NAMESPACE
21
22
void
QQuickViewPrivate::init(QQmlEngine* e)
23
{
24
Q_Q(QQuickView);
25
26
engine = e;
27
28
if
(engine.isNull())
29
engine =
new
QQmlEngine(q);
30
31
QQmlEngine::setContextForObject(contentItem, engine.data()->rootContext());
32
33
if
(!engine.data()->incubationController())
34
engine.data()->setIncubationController(q->incubationController());
35
36
{
37
// The content item has CppOwnership policy (set in QQuickWindow). Ensure the presence of a JS
38
// wrapper so that the garbage collector can see the policy.
39
QV4::ExecutionEngine *v4 = engine.data()->handle();
40
QV4::QObjectWrapper::ensureWrapper(v4, contentItem);
41
}
42
}
43
44
QQuickViewPrivate::QQuickViewPrivate()
45
: component(
nullptr
), resizeMode(QQuickView::SizeViewToRootObject), initialSize(0,0)
46
{
47
}
48
49
QQuickViewPrivate::~QQuickViewPrivate()
50
{
51
}
52
53
QQuickViewPrivate::ExecuteState QQuickViewPrivate::executeHelper()
54
{
55
if
(!engine) {
56
qWarning() <<
"QQuickView: invalid qml engine."
;
57
return
Stop;
58
}
59
60
if
(root)
61
delete
root;
62
if
(component) {
63
delete
component;
64
component =
nullptr
;
65
}
66
return
ExecuteState::Continue;
67
}
68
69
void
QQuickViewPrivate::execute()
70
{
71
if
(executeHelper() == Stop)
72
return
;
73
Q_Q(QQuickView);
74
if
(!source.isEmpty()) {
75
component =
new
QQmlComponent(engine.data(), source, q);
76
if
(!component->isLoading()) {
77
q->continueExecute();
78
}
else
{
79
QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
80
q, SLOT(continueExecute()));
81
}
82
}
83
}
84
85
void
QQuickViewPrivate::execute(QAnyStringView uri, QAnyStringView typeName)
86
{
87
if
(executeHelper() == Stop)
88
return
;
89
Q_Q(QQuickView);
90
91
component =
new
QQmlComponent(engine.data(), uri, typeName, q);
92
if
(!component->isLoading()) {
93
q->continueExecute();
94
}
else
{
95
QObject::connect(component, SIGNAL(statusChanged(QQmlComponent::Status)),
96
q, SLOT(continueExecute()));
97
}
98
99
}
100
101
void
QQuickViewPrivate::itemGeometryChanged(QQuickItem *resizeItem, QQuickGeometryChange change,
102
const
QRectF &oldGeometry)
103
{
104
Q_Q(QQuickView);
105
if
(resizeItem == root && resizeMode == QQuickView::SizeViewToRootObject) {
106
// wait for both width and height to be changed
107
resizetimer.start(0,q);
108
}
109
QQuickItemChangeListener::itemGeometryChanged(resizeItem, change, oldGeometry);
110
}
111
112
/*!
113
\class QQuickView
114
\since 5.0
115
\brief The QQuickView class provides a window for displaying a Qt Quick user interface.
116
117
\inmodule QtQuick
118
119
This is a convenience subclass of QQuickWindow which
120
will automatically load and display a QML scene when given the URL of the main source file. Alternatively,
121
you can instantiate your own objects using QQmlComponent and place them in a manually setup QQuickWindow.
122
123
Typical usage:
124
125
\snippet qquickview-ex.cpp 0
126
127
To receive errors related to loading and executing QML with QQuickView,
128
you can connect to the statusChanged() signal and monitor for QQuickView::Error.
129
The errors are available via QQuickView::errors().
130
131
QQuickView also manages sizing of the view and root object. By default, the \l resizeMode
132
is SizeViewToRootObject, which will load the component and resize it to the
133
size of the view. Alternatively the resizeMode may be set to SizeRootObjectToView which
134
will resize the view to the size of the root object.
135
136
\sa {Exposing Attributes of C++ Types to QML}, QQuickWidget
137
*/
138
139
140
/*! \fn void QQuickView::statusChanged(QQuickView::Status status)
141
This signal is emitted when the component's current \a status changes.
142
*/
143
144
/*!
145
Constructs a QQuickView with the given \a parent.
146
The default value of \a parent is 0.
147
148
*/
149
QQuickView::QQuickView(QWindow *parent)
150
: QQuickWindow(*(
new
QQuickViewPrivate), parent)
151
{
152
d_func()->init();
153
}
154
155
/*!
156
Constructs a QQuickView with the given QML \a source and \a parent.
157
The default value of \a parent is \c{nullptr}.
158
159
*/
160
QQuickView::QQuickView(
const
QUrl &source, QWindow *parent)
161
: QQuickView(parent)
162
{
163
setSource(source);
164
}
165
166
/*!
167
\since 6.7
168
Constructs a QQuickView with the element specified by \a uri and \a typeName
169
and parent \a parent.
170
The default value of \a parent is \c{nullptr}.
171
\sa loadFromModule
172
*/
173
QQuickView::QQuickView(QAnyStringView uri, QAnyStringView typeName, QWindow *parent)
174
: QQuickView(parent)
175
{
176
loadFromModule(uri, typeName);
177
}
178
179
/*!
180
Constructs a QQuickView with the given QML \a engine and \a parent.
181
182
Note: In this case, the QQuickView does not own the given \a engine object;
183
it is the caller's responsibility to destroy the engine. If the \a engine is deleted
184
before the view, status() will return QQuickView::Error.
185
186
\sa Status, status(), errors()
187
*/
188
QQuickView::QQuickView(QQmlEngine* engine, QWindow *parent)
189
: QQuickWindow(*(
new
QQuickViewPrivate), parent)
190
{
191
Q_ASSERT(engine);
192
d_func()->init(engine);
193
}
194
195
/*!
196
\internal
197
*/
198
QQuickView::QQuickView(
const
QUrl &source, QQuickRenderControl *control)
199
: QQuickWindow(*(
new
QQuickViewPrivate), control)
200
{
201
d_func()->init();
202
setSource(source);
203
}
204
205
/*!
206
Destroys the QQuickView.
207
*/
208
QQuickView::~QQuickView()
209
{
210
// Ensure that the component is destroyed before the engine; the engine may
211
// be a child of the QQuickViewPrivate, and will be destroyed by its dtor
212
Q_D(QQuickView);
213
delete
d->root;
214
}
215
216
/*!
217
\property QQuickView::source
218
\brief The URL of the source of the QML component.
219
220
Ensure that the URL provided is full and correct, in particular, use
221
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
222
223
Note that setting a source URL will result in the QML component being
224
instantiated, even if the URL is unchanged from the current value.
225
*/
226
227
/*!
228
Sets the source to the \a url, loads the QML component and instantiates it.
229
230
Ensure that the URL provided is full and correct, in particular, use
231
\l QUrl::fromLocalFile() when loading a file from the local filesystem.
232
233
Calling this method multiple times with the same url will result
234
in the QML component being reinstantiated.
235
*/
236
void
QQuickView::setSource(
const
QUrl& url)
237
{
238
Q_D(QQuickView);
239
d->source = url;
240
d->execute();
241
}
242
243
/*!
244
\since 6.7
245
Loads the QML component identified by \a uri and \a typeName. If the component
246
is backed by a QML file, \l{source} will be set accordingly. For types defined
247
in \c{C++}, \c{source} will be empty.
248
249
If any \l{source} was set before this method was called, it will be cleared.
250
251
Calling this method multiple times with the same \a uri and \a typeName will result
252
in the QML component being reinstantiated.
253
254
\sa setSource, QQmlComponent::loadFromModule, QQmlApplicationEngine::loadFromModule
255
*/
256
void
QQuickView::loadFromModule(QAnyStringView uri, QAnyStringView typeName)
257
{
258
Q_D(QQuickView);
259
d->source = {};
// clear URL
260
d->execute(uri, typeName);
261
}
262
263
/*!
264
Sets the initial properties \a initialProperties with which the QML
265
component gets initialized after calling \l QQuickView::setSource().
266
267
\snippet qquickview-ex.cpp 1
268
269
\note You can only use this function to initialize top-level properties.
270
\note This function should always be called before setSource, as it has
271
no effect once the component has become \c Ready.
272
273
\sa QQmlComponent::createWithInitialProperties()
274
\since 5.14
275
*/
276
void
QQuickView::setInitialProperties(
const
QVariantMap &initialProperties)
277
{
278
Q_D(QQuickView);
279
d->initialProperties = initialProperties;
280
}
281
282
/*!
283
\internal
284
285
Set the source \a url, \a component and content \a item (root of the QML object hierarchy) directly.
286
*/
287
void
QQuickView::setContent(
const
QUrl& url, QQmlComponent *component, QObject* item)
288
{
289
Q_D(QQuickView);
290
d->source = url;
291
d->component = component;
292
293
if
(d->component && d->component->isError()) {
294
const
QList<QQmlError> errorList = d->component->errors();
295
for
(
const
QQmlError &error : errorList) {
296
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr
).warning()
297
<< error;
298
}
299
emit statusChanged(status());
300
return
;
301
}
302
303
if
(!d->setRootObject(item))
304
delete
item;
305
emit statusChanged(status());
306
}
307
308
/*!
309
Returns the source URL, if set.
310
311
\sa setSource()
312
*/
313
QUrl QQuickView::source()
const
314
{
315
Q_D(
const
QQuickView);
316
return
d->source;
317
}
318
319
/*!
320
Returns a pointer to the QQmlEngine used for instantiating
321
QML Components.
322
*/
323
QQmlEngine* QQuickView::engine()
const
324
{
325
Q_D(
const
QQuickView);
326
return
d->engine ?
const_cast
<QQmlEngine *>(d->engine.data()) :
nullptr
;
327
}
328
329
/*!
330
This function returns the root of the context hierarchy. Each QML
331
component is instantiated in a QQmlContext. QQmlContext's are
332
essential for passing data to QML components. In QML, contexts are
333
arranged hierarchically and this hierarchy is managed by the
334
QQmlEngine.
335
*/
336
QQmlContext* QQuickView::rootContext()
const
337
{
338
Q_D(
const
QQuickView);
339
return
d->engine ? d->engine.data()->rootContext() :
nullptr
;
340
}
341
342
/*!
343
\enum QQuickView::Status
344
Specifies the loading status of the QQuickView.
345
346
\value Null This QQuickView has no source set.
347
\value Ready This QQuickView has loaded and created the QML component.
348
\value Loading This QQuickView is loading network data.
349
\value Error One or more errors has occurred. Call errors() to retrieve a list
350
of errors.
351
*/
352
353
/*! \enum QQuickView::ResizeMode
354
355
This enum specifies how to resize the view.
356
357
\value SizeViewToRootObject The view resizes with the root item in the QML.
358
\value SizeRootObjectToView The view will automatically resize the root item to the size of the view.
359
*/
360
361
/*!
362
\property QQuickView::status
363
The component's current \l{QQuickView::Status} {status}.
364
*/
365
366
QQuickView::Status QQuickView::status()
const
367
{
368
Q_D(
const
QQuickView);
369
if
(!d->engine)
370
return
QQuickView::Error;
371
372
if
(!d->component)
373
return
QQuickView::Null;
374
375
if
(d->component->status() == QQmlComponent::Ready && !d->root)
376
return
QQuickView::Error;
377
378
return
QQuickView::Status(d->component->status());
379
}
380
381
/*!
382
Return the list of errors that occurred during the last compile or create
383
operation. When the status is not Error, an empty list is returned.
384
*/
385
QList<QQmlError> QQuickView::errors()
const
386
{
387
Q_D(
const
QQuickView);
388
QList<QQmlError> errs;
389
390
if
(d->component)
391
errs = d->component->errors();
392
393
if
(!d->engine) {
394
QQmlError error;
395
error.setDescription(QLatin1String(
"QQuickView: invalid qml engine."
));
396
errs << error;
397
}
else
if
(d->component && d->component->status() == QQmlComponent::Ready && !d->root) {
398
QQmlError error;
399
error.setDescription(QLatin1String(
"QQuickView: invalid root object."
));
400
errs << error;
401
}
402
403
return
errs;
404
}
405
406
/*!
407
\property QQuickView::resizeMode
408
\brief whether the view should resize the window contents
409
410
If this property is set to SizeViewToRootObject (the default), the view
411
resizes to the size of the root item in the QML.
412
413
If this property is set to SizeRootObjectToView, the view will
414
automatically resize the root item to the size of the view.
415
416
\sa initialSize()
417
*/
418
419
void
QQuickView::setResizeMode(ResizeMode mode)
420
{
421
Q_D(QQuickView);
422
if
(d->resizeMode == mode)
423
return
;
424
425
if
(d->root) {
426
if
(d->resizeMode == SizeViewToRootObject) {
427
QQuickItemPrivate *p = QQuickItemPrivate::get(d->root);
428
p->removeItemChangeListener(d, QQuickItemPrivate::Geometry);
429
}
430
}
431
432
d->resizeMode = mode;
433
if
(d->root) {
434
d->initResize();
435
}
436
}
437
438
void
QQuickViewPrivate::initResize()
439
{
440
if
(root) {
441
if
(resizeMode == QQuickView::SizeViewToRootObject) {
442
QQuickItemPrivate *p = QQuickItemPrivate::get(root);
443
p->addItemChangeListener(
this
, QQuickItemPrivate::Geometry);
444
}
445
}
446
updateSize();
447
}
448
449
void
QQuickViewPrivate::updateSize()
450
{
451
Q_Q(QQuickView);
452
if
(!root)
453
return
;
454
455
if
(resizeMode == QQuickView::SizeViewToRootObject) {
456
QSize newSize = QSize(root->width(), root->height());
457
if
(newSize.isValid() && newSize != q->size()) {
458
q->resize(newSize);
459
}
460
}
else
if
(resizeMode == QQuickView::SizeRootObjectToView) {
461
bool
needToUpdateWidth = !qFuzzyCompare(q->width(), root->width());
462
bool
needToUpdateHeight = !qFuzzyCompare(q->height(), root->height());
463
464
if
(needToUpdateWidth && needToUpdateHeight)
465
root->setSize(QSizeF(q->width(), q->height()));
466
else
if
(needToUpdateWidth)
467
root->setWidth(q->width());
468
else
if
(needToUpdateHeight)
469
root->setHeight(q->height());
470
}
471
}
472
473
QSize QQuickViewPrivate::rootObjectSize()
const
474
{
475
QSize rootObjectSize(0,0);
476
int
widthCandidate = -1;
477
int
heightCandidate = -1;
478
if
(root) {
479
widthCandidate = root->width();
480
heightCandidate = root->height();
481
}
482
if
(widthCandidate > 0) {
483
rootObjectSize.setWidth(widthCandidate);
484
}
485
if
(heightCandidate > 0) {
486
rootObjectSize.setHeight(heightCandidate);
487
}
488
return
rootObjectSize;
489
}
490
491
QQuickView::ResizeMode QQuickView::resizeMode()
const
492
{
493
Q_D(
const
QQuickView);
494
return
d->resizeMode;
495
}
496
497
/*!
498
\internal
499
*/
500
void
QQuickView::continueExecute()
501
{
502
Q_D(QQuickView);
503
disconnect(d->component, SIGNAL(statusChanged(QQmlComponent::Status)),
this
, SLOT(continueExecute()));
504
505
if
(d->component->isError()) {
506
const
QList<QQmlError> errorList = d->component->errors();
507
for
(
const
QQmlError &error : errorList) {
508
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr
).warning()
509
<< error;
510
}
511
emit statusChanged(status());
512
return
;
513
}
514
515
std::unique_ptr<QObject> obj(d->initialProperties.empty()
516
? d->component->create()
517
: d->component->createWithInitialProperties(d->initialProperties));
518
519
if
(d->component->isError()) {
520
const
QList<QQmlError> errorList = d->component->errors();
521
for
(
const
QQmlError &error : errorList) {
522
QMessageLogger(error.url().toString().toLatin1().constData(), error.line(),
nullptr
).warning()
523
<< error;
524
}
525
emit statusChanged(status());
526
return
;
527
}
528
529
// If we used loadFromModule, we might not have a URL so far.
530
// Thus, query the component to retrieve the associated URL, if any
531
if
(d->source.isEmpty())
532
d->source = d->component->url();
533
534
if
(d->setRootObject(obj.get()))
535
Q_UNUSED(obj.release());
536
emit statusChanged(status());
537
}
538
539
540
/*!
541
\internal
542
543
Sets \a obj as root object and returns true if that operation succeeds.
544
Otherwise returns \c false. If \c false is returned, the root object is
545
\c nullptr afterwards. You can explicitly set the root object to nullptr,
546
and the return value will be \c true.
547
*/
548
bool
QQuickViewPrivate::setRootObject(QObject *obj)
549
{
550
Q_Q(QQuickView);
551
if
(root == obj)
552
return
true
;
553
554
delete
root;
555
if
(obj ==
nullptr
)
556
return
true
;
557
558
if
(QQuickItem *sgItem = qobject_cast<QQuickItem *>(obj)) {
559
root = sgItem;
560
root->setFlag(QQuickItem::ItemIsViewport);
561
sgItem->setParentItem(q->QQuickWindow::contentItem());
562
QQml_setParent_noEvent(sgItem, q->QQuickWindow::contentItem());
563
initialSize = rootObjectSize();
564
if
((resizeMode == QQuickView::SizeViewToRootObject || q->width() <= 1 || q->height() <= 1) &&
565
initialSize != q->size()) {
566
q->resize(initialSize);
567
}
568
initResize();
569
return
true
;
570
}
571
572
if
(qobject_cast<QWindow *>(obj)) {
573
qWarning() <<
"QQuickView does not support using a window as a root item."
<< Qt::endl
574
<< Qt::endl
575
<<
"If you wish to create your root window from QML, consider using QQmlApplicationEngine instead."
<< Qt::endl;
576
return
false
;
577
}
578
579
qWarning() <<
"QQuickView only supports loading of root objects that derive from QQuickItem."
<< Qt::endl
580
<< Qt::endl
581
<<
"Ensure your QML code is written for QtQuick 2, and uses a root that is or"
<< Qt::endl
582
<<
"inherits from QtQuick's Item (not a Timer, QtObject, etc)."
<< Qt::endl;
583
return
false
;
584
}
585
586
/*!
587
\internal
588
If the \l {QTimerEvent} {timer event} \a e is this
589
view's resize timer, sceneResized() is emitted.
590
*/
591
void
QQuickView::timerEvent(QTimerEvent* e)
592
{
593
Q_D(QQuickView);
594
if
(!e || e->timerId() == d->resizetimer.timerId()) {
595
d->updateSize();
596
d->resizetimer.stop();
597
}
598
}
599
600
/*!
601
\internal
602
Preferred size follows the root object geometry.
603
*/
604
QSize QQuickView::sizeHint()
const
605
{
606
Q_D(
const
QQuickView);
607
QSize rootObjectSize = d->rootObjectSize();
608
if
(rootObjectSize.isEmpty()) {
609
return
size();
610
}
else
{
611
return
rootObjectSize;
612
}
613
}
614
615
/*!
616
Returns the initial size of the root object.
617
618
If \l resizeMode is QQuickItem::SizeRootObjectToView the root object will be
619
resized to the size of the view. initialSize contains the size of the
620
root object before it was resized.
621
*/
622
QSize QQuickView::initialSize()
const
623
{
624
Q_D(
const
QQuickView);
625
return
d->initialSize;
626
}
627
628
/*!
629
Returns the view's root \l {QQuickItem} {item}.
630
*/
631
QQuickItem *QQuickView::rootObject()
const
632
{
633
Q_D(
const
QQuickView);
634
return
d->root;
635
}
636
637
/*!
638
\internal
639
This function handles the \l {QResizeEvent} {resize event}
640
\a e.
641
*/
642
void
QQuickView::resizeEvent(QResizeEvent *e)
643
{
644
Q_D(QQuickView);
645
if
(d->resizeMode == SizeRootObjectToView)
646
d->updateSize();
647
648
QQuickWindow::resizeEvent(e);
649
}
650
651
/*! \reimp */
652
void
QQuickView::keyPressEvent(QKeyEvent *e)
653
{
654
QQuickWindow::keyPressEvent(e);
655
}
656
657
/*! \reimp */
658
void
QQuickView::keyReleaseEvent(QKeyEvent *e)
659
{
660
QQuickWindow::keyReleaseEvent(e);
661
}
662
663
/*! \reimp */
664
void
QQuickView::mouseMoveEvent(QMouseEvent *e)
665
{
666
QQuickWindow::mouseMoveEvent(e);
667
}
668
669
/*! \reimp */
670
void
QQuickView::mousePressEvent(QMouseEvent *e)
671
{
672
QQuickWindow::mousePressEvent(e);
673
}
674
675
/*! \reimp */
676
void
QQuickView::mouseReleaseEvent(QMouseEvent *e)
677
{
678
QQuickWindow::mouseReleaseEvent(e);
679
}
680
681
682
QT_END_NAMESPACE
683
684
#
include
"moc_qquickview.cpp"
qtdeclarative
src
quick
items
qquickview.cpp
Generated on
for Qt by
1.18.0