Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
5#include "qquickpane_p_p.h"
7
8#include <QtQuick/private/qquickflickable_p.h>
9
11
16
94{
95public:
96 Q_DECLARE_PUBLIC(QQuickScrollView)
97
98 QQmlListProperty<QObject> contentData() override;
99 QQmlListProperty<QQuickItem> contentChildren() override;
100 QList<QQuickItem *> contentChildItems() const override;
101 QQuickItem* getFirstChild() const override;
102
103 QQuickItem *getContentItem() override;
104
105 enum class ContentItemFlag {
106 DoNotSet,
107 Set
108 };
109
112
115
116 qreal getContentWidth() const override;
117 qreal getContentHeight() const override;
118
121
122 void setScrollBarsInteractive(bool interactive);
123
124 static void contentData_append(QQmlListProperty<QObject> *prop, QObject *obj);
125 static qsizetype contentData_count(QQmlListProperty<QObject> *prop);
126 static QObject *contentData_at(QQmlListProperty<QObject> *prop, qsizetype index);
127 static void contentData_clear(QQmlListProperty<QObject> *prop);
128
129 static void contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *obj);
130 static qsizetype contentChildren_count(QQmlListProperty<QQuickItem> *prop);
131 static QQuickItem *contentChildren_at(QQmlListProperty<QQuickItem> *prop, qsizetype index);
132 static void contentChildren_clear(QQmlListProperty<QQuickItem> *prop);
133
135
138
140 bool wasTouched = false;
147};
148
150{
151 if (!flickable)
152 return QList<QQuickItem *>();
153
154 return flickable->contentItem()->childItems();
155}
156
158{
159 if (!contentItem)
161 // This function is called by QQuickControl::contentItem() to lazily create
162 // a contentItem, so we don't need to try to set it again.
164}
165
170
172{
173 Q_Q(QQuickScrollView);
174 if (!flickable) {
177 // Pass ourselves as the Flickable's parent item.
178 auto flickable = new QQuickFlickable(q);
179 // We almost always want to clip the flickable so that flickable
180 // contents doesn't show up outside the scrollview. The only time
181 // this is not really needed, is when the scrollview covers the whole
182 // window and the scrollbars are transient. But for that corner case, if this
183 // optimization is needed, the user can simply create his own flickable
184 // child inside the scrollview, and control clipping on it explicit.
185 flickable->setClip(true);
187 setFlickable(flickable, contentItemFlag);
188 }
189 return flickable;
190}
191
193{
194 Q_Q(QQuickScrollView);
195 qreal oldEffectiveScrollBarWidth = effectiveScrollBarWidth;
196 if (auto *vBar = verticalScrollBar()) {
197 if (vBar->policy() == QQuickScrollBar::AlwaysOff || !vBar->isVisible())
199 else
200 effectiveScrollBarWidth = vBar->width();
201 }
202 if (effectiveScrollBarWidth != oldEffectiveScrollBarWidth) {
203 if (!isUpdatingScrollBar) {
204 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
205 emit q->effectiveScrollBarWidthChanged();
206 }
207 }
208}
209
211{
212 Q_Q(QQuickScrollView);
213 qreal oldEffectiveScrollBarHeight = effectiveScrollBarHeight;
214 if (auto *hBar = horizontalScrollBar()) {
215 if (hBar->policy() == QQuickScrollBar::AlwaysOff || !hBar->isVisible())
217 else
218 effectiveScrollBarHeight = hBar->height();
219 }
220 if (effectiveScrollBarHeight != oldEffectiveScrollBarHeight) {
221 if (!isUpdatingScrollBar) {
222 QScopedValueRollback<bool> rollback(isUpdatingScrollBar, true);
223 emit q->effectiveScrollBarHeightChanged();
224 }
225
226 }
227}
228
243
245{
246 Q_Q(QQuickScrollView);
247 if (item == flickable)
248 return false;
249
250 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
251
252 if (flickable) {
254
255 if (attached) {
257 scrollBar->setFlickable(nullptr);
259 }
260
264 }
265
266 flickable = item;
267 if (contentItemFlag == ContentItemFlag::Set)
268 q->setContentItem(flickable);
269
270 if (flickable) {
272 if (hasContentWidth)
274 else
278 else
280
281 if (attached) {
283 scrollBar->setFlickable(flickable);
284 if (scrollBar->vertical) {
285 QObjectPrivate::connect(scrollBar->vertical, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarWidth);
287 }
288 if (scrollBar->horizontal) {
289 QObjectPrivate::connect(scrollBar->horizontal, &QQuickScrollBar::policyChanged, this, &QQuickScrollViewPrivate::updateScrollBarHeight);
291 }
292 }
293
297 }
298
299 return true;
300}
301
303{
304 Q_Q(QQuickScrollView);
306 return;
307
308 const qreal cw = flickable->contentWidth();
310 return;
311
314 emit q->implicitContentWidthChanged();
315}
316
318{
319 Q_Q(QQuickScrollView);
321 return;
322
323 const qreal ch = flickable->contentHeight();
325 return;
326
329 emit q->implicitContentHeightChanged();
330}
331
333{
335 return flickable->contentWidth();
336
337 // The scrollview wraps a flickable created by us, and nobody searched for it and
338 // modified its contentWidth. In that case, since the application does not control
339 // this flickable, we fall back to calculate the content width based on the child
340 // items inside it.
342}
343
345{
347 return flickable->contentHeight();
348
349 // The scrollview wraps a flickable created by us, and nobody searched for it and
350 // modified its contentHeight. In that case, since the application does not control
351 // this flickable, we fall back to calculate the content height based on the child
352 // items inside it.
354}
355
357{
358 Q_Q(const QQuickScrollView);
359 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
360 if (!attached)
361 return nullptr;
362 return attached->vertical();
363}
364
366{
367 Q_Q(const QQuickScrollView);
368 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(q, false));
369 if (!attached)
370 return nullptr;
371 return attached->horizontal();
372}
373
375{
377 if (hbar) {
379 if (!p->explicitInteractive)
380 p->setInteractive(interactive);
381 }
382
384 if (vbar) {
386 if (!p->explicitInteractive)
387 p->setInteractive(interactive);
388 }
389}
390
391void QQuickScrollViewPrivate::contentData_append(QQmlListProperty<QObject> *prop, QObject *obj)
392{
393 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
394 // If we don't yet have a flickable assigned, and this object is a Flickable,
395 // make it our contentItem.
396 if (!p->flickable && p->setFlickable(qobject_cast<QQuickFlickable *>(obj), ContentItemFlag::Set))
397 return;
398
399 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
401 // Add the object that was declared as a child of us as a child object of the Flickable.
402 QQmlListProperty<QObject> data = flickable->flickableData();
403 data.append(&data, obj);
404}
405
407{
408 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
409 if (!p->flickable)
410 return 0;
411
412 QQmlListProperty<QObject> data = p->flickable->flickableData();
413 return data.count(&data);
414}
415
417{
418 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
419 if (!p->flickable)
420 return nullptr;
421
422 QQmlListProperty<QObject> data = p->flickable->flickableData();
423 return data.at(&data, index);
424}
425
426void QQuickScrollViewPrivate::contentData_clear(QQmlListProperty<QObject> *prop)
427{
428 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
429 if (!p->flickable)
430 return;
431
432 QQmlListProperty<QObject> data = p->flickable->flickableData();
433 return data.clear(&data);
434}
435
436void QQuickScrollViewPrivate::contentChildren_append(QQmlListProperty<QQuickItem> *prop, QQuickItem *item)
437{
438 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
439 if (!p->flickable)
440 p->setFlickable(qobject_cast<QQuickFlickable *>(item), ContentItemFlag::Set);
441
442 QQuickFlickable *flickable = p->ensureFlickable(ContentItemFlag::Set);
444 // Add the item that was declared as a child of us as a child item of the Flickable's contentItem.
445 QQmlListProperty<QQuickItem> children = flickable->flickableChildren();
446 children.append(&children, item);
447}
448
450{
451 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
452 if (!p->flickable)
453 return 0;
454
455 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
456 return children.count(&children);
457}
458
460{
461 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
462 if (!p->flickable)
463 return nullptr;
464
465 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
466 return children.at(&children, index);
467}
468
469void QQuickScrollViewPrivate::contentChildren_clear(QQmlListProperty<QQuickItem> *prop)
470{
471 QQuickScrollViewPrivate *p = static_cast<QQuickScrollViewPrivate *>(prop->data);
472 if (!p->flickable)
473 return;
474
475 QQmlListProperty<QQuickItem> children = p->flickable->flickableChildren();
476 children.clear(&children);
477}
478
480{
481 // a special case for width<->height dependent content (wrapping text) in ScrollView
483 return;
484
486}
487
489 : QQuickPane(*(new QQuickScrollViewPrivate), parent)
490{
491 Q_D(QQuickScrollView);
492 d->contentWidth = -1;
493 d->contentHeight = -1;
494
496 setWheelEnabled(true);
497}
498
500{
501 Q_D(QQuickScrollView);
502 QQuickScrollBarAttached *attached = qobject_cast<QQuickScrollBarAttached *>(qmlAttachedPropertiesObject<QQuickScrollBar>(this, false));
503 if (attached) {
505 d->disconnectScrollBarSignals(scrollBar);
506 }
507}
508
520{
521 Q_D(QQuickScrollView);
522 return d->effectiveScrollBarWidth;
523}
524
536{
537 Q_D(QQuickScrollView);
538 return d->effectiveScrollBarHeight;
539}
540
562
583
585{
586 Q_D(QQuickScrollView);
587 switch (event->type()) {
589 d->wasTouched = true;
590 d->setScrollBarsInteractive(false);
591 return false;
592
593 case QEvent::TouchEnd:
594 d->wasTouched = false;
595 return false;
596
598 // NOTE: Flickable does not handle touch events, only synthesized mouse events
599 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized) {
600 d->wasTouched = false;
601 d->setScrollBarsInteractive(true);
602 return false;
603 }
604 return !d->wasTouched && item == d->flickable;
605
608 if (static_cast<QMouseEvent *>(event)->source() == Qt::MouseEventNotSynthesized)
609 return item == d->flickable;
610 break;
611
614 if (d->wasTouched && (item == d->verticalScrollBar() || item == d->horizontalScrollBar()))
615 d->setScrollBarsInteractive(true);
616 break;
617
618 default:
619 break;
620 }
621
622 return false;
623}
624
626{
627 Q_D(QQuickScrollView);
628 if (event->type() == QEvent::Wheel) {
629 d->setScrollBarsInteractive(true);
630 if (!d->wheelEnabled) {
631 event->ignore();
632 return true;
633 }
634 }
635 return QQuickPane::eventFilter(object, event);
636}
637
639{
640 Q_D(QQuickScrollView);
642 switch (event->key()) {
643 case Qt::Key_Up:
644 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
645 vbar->decrease();
646 event->accept();
647 }
648 break;
649 case Qt::Key_Down:
650 if (QQuickScrollBar *vbar = d->verticalScrollBar()) {
651 vbar->increase();
652 event->accept();
653 }
654 break;
655 case Qt::Key_Left:
656 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
657 hbar->decrease();
658 event->accept();
659 }
660 break;
661 case Qt::Key_Right:
662 if (QQuickScrollBar *hbar = d->horizontalScrollBar()) {
663 hbar->increase();
664 event->accept();
665 }
666 break;
667 default:
668 event->ignore();
669 break;
670 }
671}
672
680
682{
683 Q_D(QQuickScrollView);
684 if (newItem != d->flickable) {
685 // The new flickable was not created by us. In that case, we always
686 // assume/require that it has an explicit content size assigned.
687 d->flickableHasExplicitContentWidth = true;
688 d->flickableHasExplicitContentHeight = true;
689 auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(newItem);
690 if (newItem && !newItemAsFlickable)
691 qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem";
692 // This is called by QQuickControlPrivate::setContentItem_helper, so no need to
693 // try to set it as the contentItem.
694 d->setFlickable(newItemAsFlickable, QQuickScrollViewPrivate::ContentItemFlag::DoNotSet);
695 // We do, however, need to set us as its parent item, as setContentItem_helper will only
696 // do so if the item doesn't already have a parent. If newItem wasn't declared as our
697 // child and was instead imperatively assigned, it may already have a parent item,
698 // which we'll need to override.
699 if (newItem) {
700 newItem->setParentItem(this);
701
702 // Make sure that the scroll bars are stacked in front of the flickable,
703 // otherwise events won't get through to them.
704 QQuickScrollBar *verticalBar = d->verticalScrollBar();
705 if (verticalBar)
706 verticalBar->stackAfter(newItem);
707 QQuickScrollBar *horizontalBar = d->horizontalScrollBar();
708 if (horizontalBar)
709 horizontalBar->stackAfter(newItem);
710 }
711 }
712 QQuickPane::contentItemChange(newItem, oldItem);
713}
714
715void QQuickScrollView::contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
716{
717 Q_D(QQuickScrollView);
718 QQuickPane::contentSizeChange(newSize, oldSize);
719 if (d->flickable) {
720 // Only set the content size on the flickable if the flickable doesn't
721 // have an explicit assignment from before. Otherwise we can end up overwriting
722 // assignments done to those properties by the application. The
723 // exception is if the application has assigned a content size
724 // directly to the scrollview, which will then win even if the
725 // application has assigned something else to the flickable.
726 if (d->hasContentWidth || !d->flickableHasExplicitContentWidth) {
727 d->flickable->setContentWidth(newSize.width());
728 d->updateScrollBarWidth();
729 }
730 if (d->hasContentHeight || !d->flickableHasExplicitContentHeight) {
731 d->flickable->setContentHeight(newSize.height());
732 d->updateScrollBarHeight();
733 }
734 }
735}
736
737#if QT_CONFIG(accessibility)
738QAccessible::Role QQuickScrollView::accessibleRole() const
739{
740 return QAccessible::Pane;
741}
742#endif
743
745
746#include "moc_qquickscrollview_p.cpp"
\inmodule QtCore
Definition qcoreevent.h:45
@ MouseMove
Definition qcoreevent.h:63
@ MouseButtonPress
Definition qcoreevent.h:60
@ TouchBegin
Definition qcoreevent.h:241
@ HoverEnter
Definition qcoreevent.h:175
@ HoverMove
Definition qcoreevent.h:177
@ MouseButtonRelease
Definition qcoreevent.h:61
The QKeyEvent class describes a key event.
Definition qevent.h:424
T value(qsizetype i) const
Definition qlist.h:664
\inmodule QtGui
Definition qevent.h:196
static QMetaObject::Connection connect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot, Qt::ConnectionType type=Qt::AutoConnection)
Definition qobject_p.h:299
static bool disconnect(const typename QtPrivate::FunctionPointer< Func1 >::Object *sender, Func1 signal, const typename QtPrivate::FunctionPointer< Func2 >::Object *receiverPrivate, Func2 slot)
Definition qobject_p.h:328
\inmodule QtCore
Definition qobject.h:103
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2339
virtual bool eventFilter(QObject *watched, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object.
Definition qobject.cpp:1555
void removeEventFilter(QObject *obj)
Removes an event filter object obj from this object.
Definition qobject.cpp:2370
ClearFunction clear
Definition qqmllist.h:87
AtFunction at
Definition qqmllist.h:86
CountFunction count
Definition qqmllist.h:85
AppendFunction append
Definition qqmllist.h:84
QQuickDeferredPointer< QQuickItem > contentItem
virtual void executeContentItem(bool complete=false)
void setWheelEnabled(bool enabled)
void setPixelAligned(bool align)
QQmlListProperty< QObject > flickableData
void setContentWidth(qreal)
void contentWidthChanged()
void contentHeightChanged()
QQuickItem * contentItem
QQmlListProperty< QQuickItem > flickableChildren
void setContentHeight(qreal)
quint32 componentComplete
QQmlListProperty< QQuickItem > children()
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:63
void setFiltersChildMouseEvents(bool filter)
Sets whether pointer events intended for this item's children should be filtered through this item.
QList< QQuickItem * > childItems() const
Returns the children of this item.
virtual void keyPressEvent(QKeyEvent *event)
This event handler can be reimplemented in a subclass to receive key press events for an item.
void visibleChanged()
void stackAfter(const QQuickItem *)
Moves the specified sibling item to the index after this item within the list of children.
void childrenChanged()
void setClip(bool)
void contentChildrenChange()
void itemImplicitWidthChanged(QQuickItem *item) override
qreal getContentWidth() const override
qreal getContentHeight() const override
void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
virtual void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize)
static QQuickScrollBarAttachedPrivate * get(QQuickScrollBarAttached *attached)
QQuickScrollBar * horizontal
static QQuickScrollBarPrivate * get(QQuickScrollBar *bar)
static void contentData_append(QQmlListProperty< QObject > *prop, QObject *obj)
QList< QQuickItem * > contentChildItems() const override
QQmlListProperty< QObject > contentData() override
\qmlproperty list<QtObject> QtQuick.Controls::ScrollView::contentData \qmldefault
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
qreal effectiveScrollBarWidth
\qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarWidth
QQuickScrollView(QQuickItem *parent=nullptr)
qreal effectiveScrollBarHeight
\qmlproperty real QtQuick.Controls::ScrollView::effectiveScrollBarHeight
void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override
bool eventFilter(QObject *object, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
bool childMouseEventFilter(QQuickItem *item, QEvent *event) override
Reimplement this method to filter the pointer events that are received by this item's children.
void keyPressEvent(QKeyEvent *event) override
This event handler can be reimplemented in a subclass to receive key press events for an item.
void componentComplete() override
Invoked after the root component that caused this instantiation has completed construction.
void contentSizeChange(const QSizeF &newSize, const QSizeF &oldSize) override
\inmodule QtCore
Definition qsize.h:208
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
constexpr qreal height() const noexcept
Returns the height.
Definition qsize.h:335
Combined button and popup list for selecting options.
@ MouseEventNotSynthesized
@ Key_Right
Definition qnamespace.h:679
@ Key_Left
Definition qnamespace.h:677
@ Key_Up
Definition qnamespace.h:678
@ Key_Down
Definition qnamespace.h:680
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLchar * source
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLfloat GLfloat p
[1]
Q_QML_EXPORT QQmlInfo qmlWarning(const QObject *me)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static const struct TessellationWindingOrderTab cw[]
#define emit
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
QScrollBar * scrollBar
QGraphicsItem * item