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
qquickscrollview.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 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
8
9#include <QtQuick/private/qquickflickable_p.h>
10
12
13/*!
14 \qmltype ScrollView
15 \inherits Pane
16//! \nativetype QQuickScrollView
17 \inqmlmodule QtQuick.Controls
18 \since 5.9
19 \ingroup qtquickcontrols-containers
20 \ingroup qtquickcontrols-focusscopes
21 \brief Scrollable view.
22
23 ScrollView provides scrolling for user-defined content. It can be used to
24 either replace a \l Flickable, or to decorate an existing one.
25
26 \image qtquickcontrols-scrollview.png
27 {Scroll view containing scrollable content}
28
29 The first example demonstrates the simplest usage of ScrollView.
30
31 \snippet qtquickcontrols-scrollview.qml file
32
33 The second example illustrates using an existing \l Flickable, that is,
34 a \l ListView.
35
36 \snippet qtquickcontrols-scrollview-listview.qml file
37
38 \note As of Qt-6.0, ScrollView automatically clips its contents if you
39 don't use a Flickable as a child. If this is not wanted, you can
40 set your own Flickable as a child, and control the \l {Item::}{clip}
41 property on the Flickable explicitly.
42
43 \section2 Sizing
44
45 As with Flickable, there are several things to keep in mind when using
46 ScrollView:
47 \list
48 \li If only a single item is used within a ScrollView, the content size is
49 automatically calculated based on the implicit size of its contained item.
50 However, if more than one item is used (or an implicit size is not
51 provided), the \l {QtQuick.Controls::Pane::}{contentWidth} and
52 \l {QtQuick.Controls::Pane::}{contentHeight} properties must
53 be set to the combined size of its contained items.
54 \li If the content size is less than or equal to the size of the ScrollView,
55 it will not be scrollable.
56 \li If you want the ScrollView to only scroll vertically, you can bind
57 \l {QtQuick.Controls::Pane::}{contentWidth} to
58 \l {QtQuick.Controls::Control::}{availableWidth}
59 (and vice versa for contentHeight). This will let the contents fill
60 out all the available space horizontally inside the ScrollView, taking
61 any padding or scroll bars into account.
62 \endlist
63
64 \section2 Scroll Bars
65
66 The horizontal and vertical scroll bars can be accessed and customized using
67 the \l {ScrollBar::horizontal}{ScrollBar.horizontal} and \l {ScrollBar::vertical}
68 {ScrollBar.vertical} attached properties. The following example adjusts the scroll
69 bar policies so that the horizontal scroll bar is always off, and the vertical
70 scroll bar is always on.
71
72 \snippet qtquickcontrols-scrollview-policy.qml file
73
74 \section2 Touch vs. Mouse Interaction
75
76 On touch, ScrollView enables flicking and makes the scroll bars non-interactive.
77
78 \image qtquickcontrols-scrollindicator.gif
79 {Scroll indicator showing scroll position}
80
81 When interacted with a mouse device, flicking is disabled and the scroll bars
82 are interactive.
83
84 \image qtquickcontrols-scrollbar.gif
85 {Scroll bar handle moving along track}
86
87 Scroll bars can be made interactive on touch, or non-interactive when interacted
88 with a mouse device, by setting the \l {ScrollBar::}{interactive} property explicitly
89 to \c true or \c false, respectively.
90
91 \snippet qtquickcontrols-scrollview-interactive.qml file
92
93 \include varying-delegate-heights-section.qdocinc {file} {2} {ScrollBar}
94
95 \sa ScrollBar, ScrollIndicator, {Customizing ScrollView}, {Container Controls},
96 {Focus Management in Qt Quick Controls}
97*/
98
100{
101public:
102 Q_DECLARE_PUBLIC(QQuickScrollView)
103
106 QList<QQuickItem *> contentChildItems() const override;
107 QQuickItem* getFirstChild() const override;
108
110
115
116 QQuickFlickable *ensureFlickable(ContentItemFlag contentItemFlag);
117 bool setFlickable(QQuickFlickable *flickable, ContentItemFlag contentItemFlag);
118
121
122 qreal getContentWidth() const override;
123 qreal getContentHeight() const override;
124
127
128 void setScrollBarsInteractive(bool interactive);
129
130 static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
131 static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
132 static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
133 static void contentData_clear(QQmlListProperty<QObject> *prop);
134
135 static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj);
136 static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
137 static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
138 static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
139
140 void itemImplicitWidthChanged(QQuickItem *item) override;
141
144
146 bool wasTouched = false;
147 QQuickFlickable *flickable = nullptr;
153};
154
156{
157 if (!flickable)
158 return QList<QQuickItem *>();
159
160 return flickable->contentItem()->childItems();
161}
162
164{
165 if (!contentItem)
166 executeContentItem();
167 // This function is called by QQuickControl::contentItem() to lazily create
168 // a contentItem, so we don't need to try to set it again.
170}
171
173{
174 return contentChildItems().value(0);
175}
176
178{
179 Q_Q(QQuickScrollView);
180 if (!flickable) {
183 // Pass ourselves as the Flickable's parent item.
184 auto flickable = new QQuickFlickable(q);
185 // We almost always want to clip the flickable so that flickable
186 // contents doesn't show up outside the scrollview. The only time
187 // this is not really needed, is when the scrollview covers the whole
188 // window and the scrollbars are transient. But for that corner case, if this
189 // optimization is needed, the user can simply create his own flickable
190 // child inside the scrollview, and control clipping on it explicit.
191 flickable->setClip(true);
192 flickable->setPixelAligned(true);
193 setFlickable(flickable, contentItemFlag);
194 }
195 return flickable;
196}
197
199{
200 Q_Q(QQuickScrollView);
201 qreal oldEffectiveScrollBarWidth = effectiveScrollBarWidth;
202 if (auto *vBar = verticalScrollBar()) {
203 if (vBar->policy() == QQuickScrollBar::AlwaysOff || !vBar->isVisible())
204 effectiveScrollBarWidth = 0;
205 else
206 effectiveScrollBarWidth = vBar->width();
207 }
208 if (effectiveScrollBarWidth != oldEffectiveScrollBarWidth) {
209 if (!isUpdatingScrollBar) {
210 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
211 emit q->effectiveScrollBarWidthChanged();
212 }
213 }
214}
215
217{
218 Q_Q(QQuickScrollView);
219 qreal oldEffectiveScrollBarHeight = effectiveScrollBarHeight;
220 if (auto *hBar = horizontalScrollBar()) {
221 if (hBar->policy() == QQuickScrollBar::AlwaysOff || !hBar->isVisible())
222 effectiveScrollBarHeight = 0;
223 else
224 effectiveScrollBarHeight = hBar->height();
225 }
226 if (effectiveScrollBarHeight != oldEffectiveScrollBarHeight) {
227 if (!isUpdatingScrollBar) {
228 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
229 emit q->effectiveScrollBarHeightChanged();
230 }
231
232 }
233}
234
236{
237 if (!scrollBar)
238 return;
239
240 if (scrollBar->vertical) {
241 QObjectPrivate::disconnect(scrollBar->vertical, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
242 QObjectPrivate::disconnect(scrollBar->vertical, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
243 }
244 if (scrollBar->horizontal) {
245 QObjectPrivate::disconnect(scrollBar->horizontal, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
246 QObjectPrivate::disconnect(scrollBar->horizontal, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
247 }
248}
249
250bool QQuickScrollViewPrivate::setFlickable(QQuickFlickable *item, ContentItemFlag contentItemFlag)
251{
252 Q_Q(QQuickScrollView);
253 if (item == flickable)
254 return false;
255
256 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
257
258 if (flickable) {
259 flickable->removeEventFilter(q);
260
261 if (attached) {
262 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
263 scrollBar->setFlickable(nullptr);
265 }
266
267 QObjectPrivate::disconnect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
268 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
269 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
270 }
271
272 flickable = item;
273 if (contentItemFlag == ContentItemFlag::Set)
274 q->setContentItem(flickable);
275
276 if (flickable) {
277 flickable->installEventFilter(q);
278 if (hasContentWidth)
279 flickable->setContentWidth(contentWidth);
280 else
282 if (hasContentHeight)
283 flickable->setContentHeight(contentHeight);
284 else
286
287 if (attached) {
288 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
289 scrollBar->setFlickable(flickable);
290 if (scrollBar->vertical) {
291 QObjectPrivate::connect(scrollBar->vertical, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
292 QObjectPrivate::connect(scrollBar->vertical, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
293 }
294 if (scrollBar->horizontal) {
295 QObjectPrivate::connect(scrollBar->horizontal, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
296 QObjectPrivate::connect(scrollBar->horizontal, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
297 }
298 }
299
300 QObjectPrivate::connect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
301 QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
302 QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
303 }
304
305 return true;
306}
307
309{
310 Q_Q(QQuickScrollView);
311 if (!flickable || !componentComplete)
312 return;
313
314 const qreal cw = flickable->contentWidth();
315 if (qFuzzyCompare(cw, implicitContentWidth))
316 return;
317
319 implicitContentWidth = cw;
320 emit q->implicitContentWidthChanged();
321}
322
324{
325 Q_Q(QQuickScrollView);
326 if (!flickable || !componentComplete)
327 return;
328
329 const qreal ch = flickable->contentHeight();
330 if (qFuzzyCompare(ch, implicitContentHeight))
331 return;
332
334 implicitContentHeight = ch;
335 emit q->implicitContentHeightChanged();
336}
337
339{
341 return flickable->contentWidth();
342
343 // The scrollview wraps a flickable created by us, and nobody searched for it and
344 // modified its contentWidth. In that case, since the application does not control
345 // this flickable, we fall back to calculate the content width based on the child
346 // items inside it.
347 return QQuickPanePrivate::getContentWidth();
348}
349
351{
353 return flickable->contentHeight();
354
355 // The scrollview wraps a flickable created by us, and nobody searched for it and
356 // modified its contentHeight. In that case, since the application does not control
357 // this flickable, we fall back to calculate the content height based on the child
358 // items inside it.
359 return QQuickPanePrivate::getContentHeight();
360}
361
363{
364 Q_Q(const QQuickScrollView);
365 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
366 if (!attached)
367 return nullptr;
368 return attached->vertical();
369}
370
372{
373 Q_Q(const QQuickScrollView);
374 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
375 if (!attached)
376 return nullptr;
377 return attached->horizontal();
378}
379
381{
382 QQuickScrollBar *hbar = horizontalScrollBar();
383 if (hbar) {
384 QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(hbar);
386 p->setInteractive(interactive);
387 }
388
389 QQuickScrollBar *vbar = verticalScrollBar();
390 if (vbar) {
391 QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(vbar);
393 p->setInteractive(interactive);
394 }
395}
396
397void QQuickScrollViewPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
398{
399 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
400 // If we don't yet have a flickable assigned, and this object is a Flickable,
401 // make it our contentItem.
402 if (!p->flickable && p->setFlickable(qobject_cast<QQuickFlickable *>(obj), ContentItemFlag::Set))
403 return;
404
405 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
406 Q_ASSERT(flickable);
407 // Add the object that was declared as a child of us as a child object of the Flickable.
408 QQmlListProperty<QObject> data = flickable->flickableData();
409 data.append(&data, obj);
410}
411
412qsizetype QQuickScrollViewPrivate::contentData_count(QQmlListProperty<QObject> *prop)
413{
414 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
415 if (!p->flickable)
416 return 0;
417
418 QQmlListProperty<QObject> data = p->flickable->flickableData();
419 return data.count(&data);
420}
421
422QObject *QQuickScrollViewPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
423{
424 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
425 if (!p->flickable)
426 return nullptr;
427
428 QQmlListProperty<QObject> data = p->flickable->flickableData();
429 return data.at(&data, index);
430}
431
432void QQuickScrollViewPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
433{
434 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
435 if (!p->flickable)
436 return;
437
438 QQmlListProperty<QObject> data = p->flickable->flickableData();
439 return data.clear(&data);
440}
441
442void QQuickScrollViewPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
443{
444 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
445 if (!p->flickable)
446 p->setFlickable(qobject_cast<QQuickFlickable *>(item), ContentItemFlag::Set);
447
448 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
449 Q_ASSERT(flickable);
450 // Add the item that was declared as a child of us as a child item of the Flickable's contentItem.
451 QQmlListProperty<QQuickItem> children = flickable->flickableChildren();
452 children.append(&children, item);
453}
454
455qsizetype QQuickScrollViewPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
456{
457 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
458 if (!p->flickable)
459 return 0;
460
461 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
462 return children.count(&children);
463}
464
465QQuickItem *QQuickScrollViewPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index)
466{
467 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
468 if (!p->flickable)
469 return nullptr;
470
471 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
472 return children.at(&children, index);
473}
474
475void QQuickScrollViewPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
476{
477 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
478 if (!p->flickable)
479 return;
480
481 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
482 children.clear(&children);
483}
484
486{
487 // a special case for width<->height dependent content (wrapping text) in ScrollView
488 if (contentWidth < 0 && !componentComplete)
489 return;
490
491 QQuickPanePrivate::itemImplicitWidthChanged(item);
492}
493
494QQuickScrollView::QQuickScrollView(QQuickItem *parent)
495 : QQuickPane(*(new QQuickScrollViewPrivate), parent)
496{
497 Q_D(QQuickScrollView);
498 d->contentWidth = -1;
499 d->contentHeight = -1;
500
501 setFiltersChildMouseEvents(true);
502 setWheelEnabled(true);
503}
504
505QQuickScrollView::~QQuickScrollView()
506{
507 Q_D(QQuickScrollView);
508 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(this, false));
509 if (attached) {
510 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
511 d->disconnectScrollBarSignals(scrollBar);
512 }
513}
514
515/*!
516 \qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarWidth
517 \since 6.6
518
519 This property holds the effective width of the vertical scrollbar.
520 When the scrollbar is visible, this property is the current width of the
521 scrollbar. When the scroll bar is not visible or its policy is set to
522 \c QQuickScrollBar::AlwaysOff, this property is \c 0.
523
524 \sa {ScrollBar::policy}
525*/
526qreal QQuickScrollView::effectiveScrollBarWidth()
527{
528 Q_D(QQuickScrollView);
529 return d->effectiveScrollBarWidth;
530}
531
532/*!
533 \qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarHeight
534 \since 6.6
535
536 This property holds the effective height of the horizontal scrollbar.
537 When the scrollbar is visible, this property is the current height of
538 the scrollbar. When the scroll bar is not visible or its policy is set
539 to \c QQuickScrollBar::AlwaysOff, this property is \c 0.
540
541 \sa {ScrollBar::policy}
542*/
543qreal QQuickScrollView::effectiveScrollBarHeight()
544{
545 Q_D(QQuickScrollView);
546 return d->effectiveScrollBarHeight;
547}
548
549/*!
550 \qmlproperty list<QtObject> QtQuick.Controls::ScrollView::contentData
551 \qmldefault
552
553 This property holds the list of content data.
554
555 The list contains all objects that have been declared in QML as children of the view.
556
557 \note Unlike \c contentChildren, \c contentData does include non-visual QML objects.
558
559 \sa Item::data, contentChildren
560*/
561QQmlListProperty<QObject> QQuickScrollViewPrivate::contentData()
562{
563 Q_Q(QQuickScrollView);
564 return QQmlListProperty<QObject>(q, this,
565 QQuickScrollViewPrivate::contentData_append,
566 QQuickScrollViewPrivate::contentData_count,
567 QQuickScrollViewPrivate::contentData_at,
568 QQuickScrollViewPrivate::contentData_clear);
569}
570
571/*!
572 \qmlproperty list<Item> QtQuick.Controls::ScrollView::contentChildren
573
574 This property holds the list of content children.
575
576 The list contains all items that have been declared in QML as children of the view.
577
578 \note Unlike \c contentData, \c contentChildren does not include non-visual QML objects.
579
580 \sa Item::children, contentData
581*/
583{
584 Q_Q(QQuickScrollView);
585 return QQmlListProperty<QQuickItem>(q, this,
586 QQuickScrollViewPrivate::contentChildren_append,
587 QQuickScrollViewPrivate::contentChildren_count,
588 QQuickScrollViewPrivate::contentChildren_at,
589 QQuickScrollViewPrivate::contentChildren_clear);
590}
591
592bool QQuickScrollView::childMouseEventFilter(QQuickItem *item, QEvent *event)
593{
594 Q_D(QQuickScrollView);
595 switch (event->type()) {
596 case QEvent::TouchBegin:
597 d->wasTouched = true;
598 d->setScrollBarsInteractive(false);
599 return false;
600
601 case QEvent::TouchEnd:
602 d->wasTouched = false;
603 return false;
604
605 case QEvent::MouseButtonPress:
606 // NOTE: Flickable does not handle touch events, only synthesized mouse events
607 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
608 d->wasTouched = false;
609 d->setScrollBarsInteractive(true);
610 return false;
611 }
612 return !d->wasTouched && item == d->flickable;
613
614 case QEvent::MouseMove:
615 case QEvent::MouseButtonRelease:
616 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
617 return item == d->flickable;
618 break;
619
620 case QEvent::HoverEnter:
621 case QEvent::HoverMove:
622 if (d->wasTouched && (item == d->verticalScrollBar() || item == d->horizontalScrollBar()))
623 d->setScrollBarsInteractive(true);
624 break;
625
626 default:
627 break;
628 }
629
630 return false;
631}
632
633bool QQuickScrollView::eventFilter(QObject *object, QEvent *event)
634{
635 Q_D(QQuickScrollView);
636 if (event->type() == QEvent::Wheel) {
637 d->setScrollBarsInteractive(true);
638 if (!d->wheelEnabled) {
639 event->ignore();
640 return true;
641 }
642 }
643 return QQuickPane::eventFilter(object, event);
644}
645
646void QQuickScrollView::keyPressEvent(QKeyEvent *event)
647{
648 Q_D(QQuickScrollView);
649 QQuickPane::keyPressEvent(event);
650 switch (event->key()) {
651 case Qt::Key_Up:
652 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
653 vbar->decrease();
654 event->accept();
655 }
656 break;
657 case Qt::Key_Down:
658 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
659 vbar->increase();
660 event->accept();
661 }
662 break;
663 case Qt::Key_Left:
664 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
665 hbar->decrease();
666 event->accept();
667 }
668 break;
669 case Qt::Key_Right:
670 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
671 hbar->increase();
672 event->accept();
673 }
674 break;
675 default:
676 event->ignore();
677 break;
678 }
679}
680
681void QQuickScrollView::componentComplete()
682{
683 Q_D(QQuickScrollView);
684 QQuickPane::componentComplete();
685 if (!d->contentItem)
686 d->ensureFlickable(QQuickScrollViewPrivate::ContentItemFlag::Set);
687}
688
689void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
690{
691 Q_D(QQuickScrollView);
692 if (newItem != d->flickable) {
693 // The new flickable was not created by us. In that case, we always
694 // assume/require that it has an explicit content size assigned.
695 d->flickableHasExplicitContentWidth = true;
696 d->flickableHasExplicitContentHeight = true;
697 auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(newItem);
698 if (newItem && !newItemAsFlickable)
699 qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem";
700 // This is called by QQuickControlPrivate::setContentItem_helper, so no need to
701 // try to set it as the contentItem.
702 d->setFlickable(newItemAsFlickable, QQuickScrollViewPrivate::ContentItemFlag::DoNotSet);
703 // We do, however, need to set us as its parent item, as setContentItem_helper will only
704 // do so if the item doesn't already have a parent. If newItem wasn't declared as our
705 // child and was instead imperatively assigned, it may already have a parent item,
706 // which we'll need to override.
707 if (newItem) {
708 newItem->setParentItem(this);
709
710 // Make sure that the scroll bars are stacked in front of the flickable,
711 // otherwise events won't get through to them.
712 QQuickScrollBar *verticalBar = d->verticalScrollBar();
713 if (verticalBar)
714 verticalBar->stackAfter(newItem);
715 QQuickScrollBar *horizontalBar = d->horizontalScrollBar();
716 if (horizontalBar)
717 horizontalBar->stackAfter(newItem);
718 }
719 }
720 QQuickPane::contentItemChange(newItem, oldItem);
721}
722
723void QQuickScrollView::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
724{
725 Q_D(QQuickScrollView);
726 QQuickPane::contentSizeChange(newSize, oldSize);
727 if (d->flickable) {
728 // Only set the content size on the flickable if the flickable doesn't
729 // have an explicit assignment from before. Otherwise we can end up overwriting
730 // assignments done to those properties by the application. The
731 // exception is if the application has assigned a content size
732 // directly to the scrollview, which will then win even if the
733 // application has assigned something else to the flickable.
734 if (d->hasContentWidth || !d->flickableHasExplicitContentWidth) {
735 d->flickable->setContentWidth(newSize.width());
736 d->updateScrollBarWidth();
737 }
738 if (d->hasContentHeight || !d->flickableHasExplicitContentHeight) {
739 d->flickable->setContentHeight(newSize.height());
740 d->updateScrollBarHeight();
741 }
742 }
743}
744
745#if QT_CONFIG(accessibility)
746QAccessible::Role QQuickScrollView::accessibleRole() const
747{
748 return QAccessible::Pane;
749}
750#endif
751
752QT_END_NAMESPACE
753
754#include "moc_qquickscrollview_p.cpp"
void setInteractive(bool interactive)
static void contentData_append(QQmlListProperty< QObject > *prop, QObject *obj)
QList< QQuickItem * > contentChildItems() const override
static qsizetype contentData_count(QQmlListProperty< QObject > *prop)
static void contentChildren_clear(QQmlListProperty< QQuickItem > *prop)
static QQuickItem * contentChildren_at(QQmlListProperty< QQuickItem > *prop, qsizetype index)
QQuickFlickable * ensureFlickable(ContentItemFlag contentItemFlag)
void setScrollBarsInteractive(bool interactive)
static qsizetype contentChildren_count(QQmlListProperty< QQuickItem > *prop)
static void contentChildren_append(QQmlListProperty< QQuickItem > *prop, QQuickItem *obj)
qreal getContentHeight() const override
static QObject * contentData_at(QQmlListProperty< QObject > *prop, qsizetype index)
void disconnectScrollBarSignals(QQuickScrollBarAttachedPrivate *scrollBar)
void itemImplicitWidthChanged(QQuickItem *item) override
QQuickScrollBar * verticalScrollBar() const
qreal getContentWidth() const override
QQuickItem * getContentItem() override
QQuickItem * getFirstChild() const override
QQuickScrollBar * horizontalScrollBar() const
static void contentData_clear(QQmlListProperty< QObject > *prop)
bool setFlickable(QQuickFlickable *flickable, ContentItemFlag contentItemFlag)
QQmlListProperty< QQuickItem > contentChildren() override
\qmlproperty list<Item> QtQuick.Controls::ScrollView::contentChildren
Combined button and popup list for selecting options.