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 void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
142
145
147 bool wasTouched = false;
148 QQuickFlickable *flickable = nullptr;
154};
155
157{
158 if (!flickable)
159 return QList<QQuickItem *>();
160
161 return flickable->contentItem()->childItems();
162}
163
165{
166 if (!contentItem)
167 executeContentItem();
168 // This function is called by QQuickControl::contentItem() to lazily create
169 // a contentItem, so we don't need to try to set it again.
171}
172
174{
175 return contentChildItems().value(0);
176}
177
179{
180 Q_Q(QQuickScrollView);
181 if (!flickable) {
184 // Pass ourselves as the Flickable's parent item.
185 auto flickable = new QQuickFlickable(q);
186 // We almost always want to clip the flickable so that flickable
187 // contents doesn't show up outside the scrollview. The only time
188 // this is not really needed, is when the scrollview covers the whole
189 // window and the scrollbars are transient. But for that corner case, if this
190 // optimization is needed, the user can simply create his own flickable
191 // child inside the scrollview, and control clipping on it explicit.
192 flickable->setClip(true);
193 flickable->setPixelAligned(true);
194 setFlickable(flickable, contentItemFlag);
195 }
196 return flickable;
197}
198
200{
201 Q_Q(QQuickScrollView);
202 qreal oldEffectiveScrollBarWidth = effectiveScrollBarWidth;
203 if (auto *vBar = verticalScrollBar()) {
204 if (vBar->policy() == QQuickScrollBar::AlwaysOff || !vBar->isVisible())
205 effectiveScrollBarWidth = 0;
206 else
207 effectiveScrollBarWidth = vBar->width();
208 }
209 if (effectiveScrollBarWidth != oldEffectiveScrollBarWidth) {
210 if (!isUpdatingScrollBar) {
211 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
212 emit q->effectiveScrollBarWidthChanged();
213 }
214 }
215}
216
218{
219 Q_Q(QQuickScrollView);
220 qreal oldEffectiveScrollBarHeight = effectiveScrollBarHeight;
221 if (auto *hBar = horizontalScrollBar()) {
222 if (hBar->policy() == QQuickScrollBar::AlwaysOff || !hBar->isVisible())
223 effectiveScrollBarHeight = 0;
224 else
225 effectiveScrollBarHeight = hBar->height();
226 }
227 if (effectiveScrollBarHeight != oldEffectiveScrollBarHeight) {
228 if (!isUpdatingScrollBar) {
229 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
230 emit q->effectiveScrollBarHeightChanged();
231 }
232
233 }
234}
235
237{
238 if (!scrollBar)
239 return;
240
241 if (scrollBar->vertical) {
242 QObjectPrivate::disconnect(scrollBar->vertical, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
243 QObjectPrivate::disconnect(scrollBar->vertical, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
244 QQuickItemPrivate::get(scrollBar->vertical)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
245 }
246 if (scrollBar->horizontal) {
247 QObjectPrivate::disconnect(scrollBar->horizontal, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
248 QObjectPrivate::disconnect(scrollBar->horizontal, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
249 QQuickItemPrivate::get(scrollBar->horizontal)->removeItemChangeListener(this, QQuickItemPrivate::Geometry);
250 }
251}
252
253bool QQuickScrollViewPrivate::setFlickable(QQuickFlickable *item, ContentItemFlag contentItemFlag)
254{
255 Q_Q(QQuickScrollView);
256 if (item == flickable)
257 return false;
258
259 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
260
261 if (flickable) {
262 flickable->removeEventFilter(q);
263
264 if (attached) {
265 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
266 scrollBar->setFlickable(nullptr);
268 }
269
270 QObjectPrivate::disconnect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
271 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
272 QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
273 }
274
275 flickable = item;
276 if (contentItemFlag == ContentItemFlag::Set)
277 q->setContentItem(flickable);
278
279 if (flickable) {
280 flickable->installEventFilter(q);
281 if (hasContentWidth)
282 flickable->setContentWidth(contentWidth);
283 else
285 if (hasContentHeight)
286 flickable->setContentHeight(contentHeight);
287 else
289
290 if (attached) {
291 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
292 scrollBar->setFlickable(flickable);
293 if (scrollBar->vertical) {
294 QObjectPrivate::connect(scrollBar->vertical, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
295 QObjectPrivate::connect(scrollBar->vertical, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
296 QQuickItemPrivate::get(scrollBar->vertical)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
297 }
298 if (scrollBar->horizontal) {
299 QObjectPrivate::connect(scrollBar->horizontal, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
300 QObjectPrivate::connect(scrollBar->horizontal, &QQuickScrollBar::visibleChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
301 QQuickItemPrivate::get(scrollBar->horizontal)->addItemChangeListener(this, QQuickItemPrivate::Geometry);
302 }
303 }
304
305 QObjectPrivate::connect(flickable->contentItem(), &QQuickItem::childrenChanged, this, &QQuickPanePrivate::contentChildrenChange);
306 QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickScrollViewPrivate::flickableContentWidthChanged);
307 QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickScrollViewPrivate::flickableContentHeightChanged);
308 }
309
310 return true;
311}
312
314{
315 Q_Q(QQuickScrollView);
316 if (!flickable || !componentComplete)
317 return;
318
319 const qreal cw = flickable->contentWidth();
320 if (qFuzzyCompare(cw, implicitContentWidth))
321 return;
322
324 implicitContentWidth = cw;
325 emit q->implicitContentWidthChanged();
326}
327
329{
330 Q_Q(QQuickScrollView);
331 if (!flickable || !componentComplete)
332 return;
333
334 const qreal ch = flickable->contentHeight();
335 if (qFuzzyCompare(ch, implicitContentHeight))
336 return;
337
339 implicitContentHeight = ch;
340 emit q->implicitContentHeightChanged();
341}
342
344{
346 return flickable->contentWidth();
347
348 // The scrollview wraps a flickable created by us, and nobody searched for it and
349 // modified its contentWidth. In that case, since the application does not control
350 // this flickable, we fall back to calculate the content width based on the child
351 // items inside it.
352 return QQuickPanePrivate::getContentWidth();
353}
354
356{
358 return flickable->contentHeight();
359
360 // The scrollview wraps a flickable created by us, and nobody searched for it and
361 // modified its contentHeight. In that case, since the application does not control
362 // this flickable, we fall back to calculate the content height based on the child
363 // items inside it.
364 return QQuickPanePrivate::getContentHeight();
365}
366
368{
369 Q_Q(const QQuickScrollView);
370 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
371 if (!attached)
372 return nullptr;
373 return attached->vertical();
374}
375
377{
378 Q_Q(const QQuickScrollView);
379 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
380 if (!attached)
381 return nullptr;
382 return attached->horizontal();
383}
384
386{
387 QQuickScrollBar *hbar = horizontalScrollBar();
388 if (hbar) {
389 QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(hbar);
391 p->setInteractive(interactive);
392 }
393
394 QQuickScrollBar *vbar = verticalScrollBar();
395 if (vbar) {
396 QQuickScrollBarPrivate *p = QQuickScrollBarPrivate::get(vbar);
398 p->setInteractive(interactive);
399 }
400}
401
402void QQuickScrollViewPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
403{
404 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
405 // If we don't yet have a flickable assigned, and this object is a Flickable,
406 // make it our contentItem.
407 if (!p->flickable && p->setFlickable(qobject_cast<QQuickFlickable *>(obj), ContentItemFlag::Set))
408 return;
409
410 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
411 Q_ASSERT(flickable);
412 // Add the object that was declared as a child of us as a child object of the Flickable.
413 QQmlListProperty<QObject> data = flickable->flickableData();
414 data.append(&data, obj);
415}
416
417qsizetype QQuickScrollViewPrivate::contentData_count(QQmlListProperty<QObject> *prop)
418{
419 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
420 if (!p->flickable)
421 return 0;
422
423 QQmlListProperty<QObject> data = p->flickable->flickableData();
424 return data.count(&data);
425}
426
427QObject *QQuickScrollViewPrivate::contentData_at(QQmlListProperty<QObject> *prop, qsizetype index)
428{
429 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
430 if (!p->flickable)
431 return nullptr;
432
433 QQmlListProperty<QObject> data = p->flickable->flickableData();
434 return data.at(&data, index);
435}
436
437void QQuickScrollViewPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
438{
439 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
440 if (!p->flickable)
441 return;
442
443 QQmlListProperty<QObject> data = p->flickable->flickableData();
444 return data.clear(&data);
445}
446
447void QQuickScrollViewPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
448{
449 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
450 if (!p->flickable)
451 p->setFlickable(qobject_cast<QQuickFlickable *>(item), ContentItemFlag::Set);
452
453 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
454 Q_ASSERT(flickable);
455 // Add the item that was declared as a child of us as a child item of the Flickable's contentItem.
456 QQmlListProperty<QQuickItem> children = flickable->flickableChildren();
457 children.append(&children, item);
458}
459
460qsizetype QQuickScrollViewPrivate::contentChildren_count(QQmlListProperty<QQuickItem> *prop)
461{
462 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
463 if (!p->flickable)
464 return 0;
465
466 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
467 return children.count(&children);
468}
469
470QQuickItem *QQuickScrollViewPrivate::contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index)
471{
472 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
473 if (!p->flickable)
474 return nullptr;
475
476 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
477 return children.at(&children, index);
478}
479
480void QQuickScrollViewPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
481{
482 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
483 if (!p->flickable)
484 return;
485
486 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
487 children.clear(&children);
488}
489
491{
492 // a special case for width<->height dependent content (wrapping text) in ScrollView
493 if (contentWidth < 0 && !componentComplete)
494 return;
495
496 QQuickPanePrivate::itemImplicitWidthChanged(item);
497}
498
499void QQuickScrollViewPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
500{
501 QQuickPanePrivate::itemGeometryChanged(item, change, diff);
502 if (change.widthChange() && item == verticalScrollBar())
504 else if (change.heightChange() && item == horizontalScrollBar())
506}
507
508QQuickScrollView::QQuickScrollView(QQuickItem *parent)
509 : QQuickPane(*(new QQuickScrollViewPrivate), parent)
510{
511 Q_D(QQuickScrollView);
512 d->contentWidth = -1;
513 d->contentHeight = -1;
514
515 setFiltersChildMouseEvents(true);
516 setWheelEnabled(true);
517}
518
519QQuickScrollView::~QQuickScrollView()
520{
521 Q_D(QQuickScrollView);
522 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(this, false));
523 if (attached) {
524 auto *scrollBar = QQuickScrollBarAttachedPrivate::get(attached);
525 d->disconnectScrollBarSignals(scrollBar);
526 }
527}
528
529/*!
530 \qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarWidth
531 \since 6.6
532
533 This property holds the effective width of the vertical scrollbar.
534 When the scrollbar is visible, this property is the current width of the
535 scrollbar. When the scroll bar is not visible or its policy is set to
536 \c QQuickScrollBar::AlwaysOff, this property is \c 0.
537
538 \sa {ScrollBar::policy}
539*/
540qreal QQuickScrollView::effectiveScrollBarWidth()
541{
542 Q_D(QQuickScrollView);
543 return d->effectiveScrollBarWidth;
544}
545
546/*!
547 \qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarHeight
548 \since 6.6
549
550 This property holds the effective height of the horizontal scrollbar.
551 When the scrollbar is visible, this property is the current height of
552 the scrollbar. When the scroll bar is not visible or its policy is set
553 to \c QQuickScrollBar::AlwaysOff, this property is \c 0.
554
555 \sa {ScrollBar::policy}
556*/
557qreal QQuickScrollView::effectiveScrollBarHeight()
558{
559 Q_D(QQuickScrollView);
560 return d->effectiveScrollBarHeight;
561}
562
563/*!
564 \qmlproperty list<QtObject> QtQuick.Controls::ScrollView::contentData
565 \qmldefault
566
567 This property holds the list of content data.
568
569 The list contains all objects that have been declared in QML as children of the view.
570
571 \note Unlike \c contentChildren, \c contentData does include non-visual QML objects.
572
573 \sa Item::data, contentChildren
574*/
575QQmlListProperty<QObject> QQuickScrollViewPrivate::contentData()
576{
577 Q_Q(QQuickScrollView);
578 return QQmlListProperty<QObject>(q, this,
579 QQuickScrollViewPrivate::contentData_append,
580 QQuickScrollViewPrivate::contentData_count,
581 QQuickScrollViewPrivate::contentData_at,
582 QQuickScrollViewPrivate::contentData_clear);
583}
584
585/*!
586 \qmlproperty list<Item> QtQuick.Controls::ScrollView::contentChildren
587
588 This property holds the list of content children.
589
590 The list contains all items that have been declared in QML as children of the view.
591
592 \note Unlike \c contentData, \c contentChildren does not include non-visual QML objects.
593
594 \sa Item::children, contentData
595*/
597{
598 Q_Q(QQuickScrollView);
599 return QQmlListProperty<QQuickItem>(q, this,
600 QQuickScrollViewPrivate::contentChildren_append,
601 QQuickScrollViewPrivate::contentChildren_count,
602 QQuickScrollViewPrivate::contentChildren_at,
603 QQuickScrollViewPrivate::contentChildren_clear);
604}
605
606bool QQuickScrollView::childMouseEventFilter(QQuickItem *item, QEvent *event)
607{
608 Q_D(QQuickScrollView);
609 switch (event->type()) {
610 case QEvent::TouchBegin:
611 d->wasTouched = true;
612 d->setScrollBarsInteractive(false);
613 return false;
614
615 case QEvent::TouchEnd:
616 d->wasTouched = false;
617 return false;
618
619 case QEvent::MouseButtonPress:
620 // NOTE: Flickable does not handle touch events, only synthesized mouse events
621 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
622 d->wasTouched = false;
623 d->setScrollBarsInteractive(true);
624 return false;
625 }
626 return !d->wasTouched && item == d->flickable;
627
628 case QEvent::MouseMove:
629 case QEvent::MouseButtonRelease:
630 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
631 return item == d->flickable;
632 break;
633
634 case QEvent::HoverEnter:
635 case QEvent::HoverMove:
636 if (d->wasTouched && (item == d->verticalScrollBar() || item == d->horizontalScrollBar()))
637 d->setScrollBarsInteractive(true);
638 break;
639
640 default:
641 break;
642 }
643
644 return false;
645}
646
647bool QQuickScrollView::eventFilter(QObject *object, QEvent *event)
648{
649 Q_D(QQuickScrollView);
650 if (event->type() == QEvent::Wheel) {
651 d->setScrollBarsInteractive(true);
652 if (!d->wheelEnabled) {
653 event->ignore();
654 return true;
655 }
656 }
657 return QQuickPane::eventFilter(object, event);
658}
659
660void QQuickScrollView::keyPressEvent(QKeyEvent *event)
661{
662 Q_D(QQuickScrollView);
663 QQuickPane::keyPressEvent(event);
664 switch (event->key()) {
665 case Qt::Key_Up:
666 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
667 vbar->decrease();
668 event->accept();
669 }
670 break;
671 case Qt::Key_Down:
672 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
673 vbar->increase();
674 event->accept();
675 }
676 break;
677 case Qt::Key_Left:
678 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
679 hbar->decrease();
680 event->accept();
681 }
682 break;
683 case Qt::Key_Right:
684 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
685 hbar->increase();
686 event->accept();
687 }
688 break;
689 default:
690 event->ignore();
691 break;
692 }
693}
694
695void QQuickScrollView::componentComplete()
696{
697 Q_D(QQuickScrollView);
698 QQuickPane::componentComplete();
699 if (!d->contentItem)
700 d->ensureFlickable(QQuickScrollViewPrivate::ContentItemFlag::Set);
701}
702
703void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
704{
705 Q_D(QQuickScrollView);
706 if (newItem != d->flickable) {
707 // The new flickable was not created by us. In that case, we always
708 // assume/require that it has an explicit content size assigned.
709 d->flickableHasExplicitContentWidth = true;
710 d->flickableHasExplicitContentHeight = true;
711 auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(newItem);
712 if (newItem && !newItemAsFlickable)
713 qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem";
714 // This is called by QQuickControlPrivate::setContentItem_helper, so no need to
715 // try to set it as the contentItem.
716 d->setFlickable(newItemAsFlickable, QQuickScrollViewPrivate::ContentItemFlag::DoNotSet);
717 // We do, however, need to set us as its parent item, as setContentItem_helper will only
718 // do so if the item doesn't already have a parent. If newItem wasn't declared as our
719 // child and was instead imperatively assigned, it may already have a parent item,
720 // which we'll need to override.
721 if (newItem) {
722 newItem->setParentItem(this);
723
724 // Make sure that the scroll bars are stacked in front of the flickable,
725 // otherwise events won't get through to them.
726 QQuickScrollBar *verticalBar = d->verticalScrollBar();
727 if (verticalBar)
728 verticalBar->stackAfter(newItem);
729 QQuickScrollBar *horizontalBar = d->horizontalScrollBar();
730 if (horizontalBar)
731 horizontalBar->stackAfter(newItem);
732 }
733 }
734 QQuickPane::contentItemChange(newItem, oldItem);
735}
736
737void QQuickScrollView::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
738{
739 Q_D(QQuickScrollView);
740 QQuickPane::contentSizeChange(newSize, oldSize);
741 if (d->flickable) {
742 // Only set the content size on the flickable if the flickable doesn't
743 // have an explicit assignment from before. Otherwise we can end up overwriting
744 // assignments done to those properties by the application. The
745 // exception is if the application has assigned a content size
746 // directly to the scrollview, which will then win even if the
747 // application has assigned something else to the flickable.
748 if (d->hasContentWidth || !d->flickableHasExplicitContentWidth) {
749 d->flickable->setContentWidth(newSize.width());
750 d->updateScrollBarWidth();
751 }
752 if (d->hasContentHeight || !d->flickableHasExplicitContentHeight) {
753 d->flickable->setContentHeight(newSize.height());
754 d->updateScrollBarHeight();
755 }
756 }
757}
758
759#if QT_CONFIG(accessibility)
760QAccessible::Role QQuickScrollView::accessibleRole() const
761{
762 return QAccessible::Pane;
763}
764#endif
765
766QT_END_NAMESPACE
767
768#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
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override
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.