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
qquicktabbar.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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
10
11/*!
12 \qmltype TabBar
13 \inherits Container
14//! \nativetype QQuickTabBar
15 \inqmlmodule QtQuick.Controls
16 \since 5.7
17 \ingroup qtquickcontrols-navigation
18 \ingroup qtquickcontrols-containers
19 \ingroup qtquickcontrols-focusscopes
20 \brief Allows the user to switch between different views or subtasks.
21
22 TabBar provides a tab-based navigation model.
23
24 \image qtquickcontrols-tabbar-wireframe.webp
25
26 TabBar is populated with TabButton controls, and can be used together with
27 any layout or container control that provides \c currentIndex -property,
28 such as \l StackLayout or \l SwipeView
29
30 \snippet qtquickcontrols-tabbar.qml 1
31
32 As shown above, TabBar is typically populated with a static set of tab buttons
33 that are defined inline as children of the tab bar. It is also possible to
34 \l {Container::addItem()}{add}, \l {Container::insertItem()}{insert},
35 \l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
36 items dynamically at run time. The items can be accessed using
37 \l {Container::}{itemAt()} or \l {Container::}{contentChildren}.
38
39 \include container-currentindex.qdocinc {file} {TabBar} {SwipeView}
40
41 \section2 Resizing Tabs
42
43 By default, TabBar resizes its buttons to fit the width of the control.
44 The available space is distributed equally to each button. The default
45 resizing behavior can be overridden by setting an explicit width for the
46 buttons.
47
48 The following example illustrates how to keep each tab button at their
49 implicit size instead of being resized to fit the tabbar:
50
51 \borderedimage qtquickcontrols-tabbar-explicit.png
52
53 \snippet qtquickcontrols-tabbar-explicit.qml 1
54
55 \section2 Flickable Tabs
56
57 If the total width of the buttons exceeds the available width of the tab bar,
58 it automatically becomes flickable.
59
60 \image qtquickcontrols-tabbar-flickable.png
61
62 \snippet qtquickcontrols-tabbar-flickable.qml 1
63
64 \sa TabButton, {Customizing TabBar}, {Navigation Controls}, {Container Controls},
65 {Focus Management in Qt Quick Controls}
66*/
67
69{
70public:
71 Q_DECLARE_PUBLIC(QQuickTabBar)
72
76
77 qreal getContentWidth() const override;
78 qreal getContentHeight() const override;
79
80 void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
81 void itemImplicitWidthChanged(QQuickItem *item) override;
82 void itemImplicitHeightChanged(QQuickItem *item) override;
83
84 QPalette defaultPalette() const override { return QQuickTheme::palette(QQuickTheme::TabBar); }
85
86 bool updatingLayout = false;
88#if QT_CONFIG(wheelevent)
90#endif
91};
92
94{
95 Q_DECLARE_PUBLIC(QQuickTabBarAttached)
96
97public:
102
104
105 int index = -1;
107};
108
109void QQuickTabBarPrivate::updateCurrentItem()
110{
111 QQuickTabButton *button = qobject_cast<QQuickTabButton *>(contentModel->get(currentIndex));
112 if (button)
113 button->setChecked(true);
114}
115
117{
118 Q_Q(QQuickTabBar);
119 QQuickTabButton *button = qobject_cast<QQuickTabButton *>(q->sender());
120 if (button && button->isChecked())
121 q->setCurrentIndex(contentModel->indexOf(button, nullptr));
122}
123
125{
126 Q_Q(QQuickTabBar);
127 const int count = contentModel->count();
128 if (count <= 0 || !contentItem)
129 return;
130
131 qreal reservedWidth = 0;
132 int resizableCount = 0;
133
134 QList<QQuickItem *> allItems;
135 allItems.reserve(count);
136
137 for (int i = 0; i < count; ++i) {
138 QQuickItem *item = q->itemAt(i);
139 if (item) {
140 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
141 if (!p->widthValid())
142 ++resizableCount;
143 else
144 reservedWidth += item->width();
145 allItems += item;
146 }
147 }
148
149 const qreal totalSpacing = qMax(0, count - 1) * spacing;
150 const qreal itemWidth = (contentItem->width() - reservedWidth - totalSpacing) / qMax(1, resizableCount);
151
152 updatingLayout = true;
153 for (QQuickItem *item : std::as_const(allItems)) {
154 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
155 if (!p->widthValid()) {
156 item->setWidth(itemWidth);
157 p->widthValidFlag = false;
158 }
159 if (!p->heightValid()) {
160 item->setHeight(contentHeight);
161 p->heightValidFlag = false;
162 } else {
163 item->setY((contentHeight - item->height()) / 2);
164 }
165 }
166 updatingLayout = false;
167}
168
170{
171 if (hasContentWidth)
172 return contentWidth;
173
174 Q_Q(const QQuickTabBar);
175 const int count = contentModel->count();
176 qreal totalWidth = qMax(0, count - 1) * spacing;
177 for (int i = 0; i < count; ++i) {
178 QQuickItem *item = q->itemAt(i);
179 if (item) {
180 QQuickItemPrivate *p = QQuickItemPrivate::get(item);
181 if (!p->widthValid())
182 totalWidth += item->implicitWidth();
183 else
184 totalWidth += item->width();
185 }
186 }
187 return totalWidth;
188}
189
191{
192 if (hasContentHeight)
193 return contentHeight;
194
195 Q_Q(const QQuickTabBar);
196 const int count = contentModel->count();
197 qreal maxHeight = 0;
198 for (int i = 0; i < count; ++i) {
199 QQuickItem *item = q->itemAt(i);
200 if (item)
201 maxHeight = qMax(maxHeight, item->implicitHeight());
202 }
203 return maxHeight;
204}
205
206void QQuickTabBarPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
207{
208 QQuickContainerPrivate::itemGeometryChanged(item, change, diff);
209 if (!updatingLayout) {
210 if (change.sizeChange())
211 updateImplicitContentSize();
213 }
214}
215
217{
218 QQuickContainerPrivate::itemImplicitWidthChanged(item);
219 if (item != contentItem)
220 updateImplicitContentWidth();
221}
222
224{
225 QQuickContainerPrivate::itemImplicitHeightChanged(item);
226 if (item != contentItem)
227 updateImplicitContentHeight();
228}
229
230QQuickTabBar::QQuickTabBar(QQuickItem *parent)
231 : QQuickContainer(*(new QQuickTabBarPrivate), parent)
232{
233 Q_D(QQuickTabBar);
234 d->changeTypes |= QQuickItemPrivate::Geometry | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
235 setFlag(ItemIsFocusScope);
236 QObjectPrivate::connect(this, &QQuickTabBar::currentIndexChanged, d, &QQuickTabBarPrivate::updateCurrentItem);
237}
238
239/*!
240 \qmlproperty enumeration QtQuick.Controls::TabBar::position
241
242 This property holds the position of the tab bar.
243
244 \note If the tab bar is assigned as a header or footer of \l ApplicationWindow
245 or \l Page, the appropriate position is set automatically.
246
247 Possible values:
248 \value TabBar.Header The tab bar is at the top, as a window or page header.
249 \value TabBar.Footer The tab bar is at the bottom, as a window or page footer.
250
251 The default value is style-specific.
252
253 \sa ApplicationWindow::header, ApplicationWindow::footer, Page::header, Page::footer
254*/
255QQuickTabBar::Position QQuickTabBar::position() const
256{
257 Q_D(const QQuickTabBar);
258 return d->position;
259}
260
261void QQuickTabBar::setPosition(Position position)
262{
263 Q_D(QQuickTabBar);
264 if (d->position == position)
265 return;
266
267 d->position = position;
268 emit positionChanged();
269}
270
271/*!
272 \since QtQuick.Controls 2.2 (Qt 5.9)
273 \qmlproperty real QtQuick.Controls::TabBar::contentWidth
274
275 This property holds the content width. It is used for calculating the total
276 implicit width of the tab bar.
277
278 \note This property is available in TabBar since QtQuick.Controls 2.2 (Qt 5.9),
279 but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
280
281 \sa Container::contentWidth
282*/
283
284/*!
285 \since QtQuick.Controls 2.2 (Qt 5.9)
286 \qmlproperty real QtQuick.Controls::TabBar::contentHeight
287
288 This property holds the content height. It is used for calculating the total
289 implicit height of the tab bar.
290
291 \note This property is available in TabBar since QtQuick.Controls 2.2 (Qt 5.9),
292 but it was promoted to the Container base type in QtQuick.Controls 2.5 (Qt 5.12).
293
294 \sa Container::contentHeight
295*/
296
297QQuickTabBarAttached *QQuickTabBar::qmlAttachedProperties(QObject *object)
298{
299 return new QQuickTabBarAttached(object);
300}
301
302void QQuickTabBar::updatePolish()
303{
304 Q_D(QQuickTabBar);
305 QQuickContainer::updatePolish();
306 d->updateLayout();
307}
308
309void QQuickTabBar::componentComplete()
310{
311 Q_D(QQuickTabBar);
312 QQuickContainer::componentComplete();
313 d->updateCurrentItem();
314 d->updateLayout();
315}
316
317void QQuickTabBar::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
318{
319 Q_D(QQuickTabBar);
320 QQuickContainer::geometryChange(newGeometry, oldGeometry);
321 d->updateLayout();
322}
323
324bool QQuickTabBar::isContent(QQuickItem *item) const
325{
326 return qobject_cast<QQuickTabButton *>(item);
327}
328
329void QQuickTabBar::itemAdded(int index, QQuickItem *item)
330{
331 Q_D(QQuickTabBar);
332 Q_UNUSED(index);
333 QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-55129
334 if (QQuickTabButton *button = qobject_cast<QQuickTabButton *>(item))
335 QObjectPrivate::connect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex);
336 QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
337 if (attached)
338 QQuickTabBarAttachedPrivate::get(attached)->update(this, index);
339 d->updateImplicitContentSize();
340 if (isComponentComplete())
341 polish();
342}
343
344void QQuickTabBar::itemMoved(int index, QQuickItem *item)
345{
346 QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
347 if (attached)
348 QQuickTabBarAttachedPrivate::get(attached)->update(this, index);
349}
350
351void QQuickTabBar::itemRemoved(int index, QQuickItem *item)
352{
353 Q_D(QQuickTabBar);
354 Q_UNUSED(index);
355 if (QQuickTabButton *button = qobject_cast<QQuickTabButton *>(item))
356 QObjectPrivate::disconnect(button, &QQuickTabButton::checkedChanged, d, &QQuickTabBarPrivate::updateCurrentIndex);
357 QQuickTabBarAttached *attached = qobject_cast<QQuickTabBarAttached *>(qmlAttachedPropertiesObject<QQuickTabBar>(item));
358 if (attached)
359 QQuickTabBarAttachedPrivate::get(attached)->update(nullptr, -1);
360 d->updateImplicitContentSize();
361 if (isComponentComplete())
362 polish();
363}
364
365#if QT_CONFIG(wheelevent)
366void QQuickTabBar::wheelEvent(QWheelEvent *event)
367{
368 Q_D(QQuickTabBar);
369 QQuickContainer::wheelEvent(event);
370 if (d->wheelEnabled) {
371 d->accumulatedAngleDelta += event->angleDelta();
372 int xSteps = d->accumulatedAngleDelta.x() / QWheelEvent::DefaultDeltasPerStep;
373 int ySteps = d->accumulatedAngleDelta.y() / QWheelEvent::DefaultDeltasPerStep;
374 if (xSteps > 0 || ySteps > 0) {
375 decrementCurrentIndex();
376 d->accumulatedAngleDelta = QPoint();
377 } else if (xSteps < 0 || ySteps < 0) {
378 incrementCurrentIndex();
379 d->accumulatedAngleDelta = QPoint();
380 }
381 }
382}
383#endif
384
385QFont QQuickTabBar::defaultFont() const
386{
387 return QQuickTheme::font(QQuickTheme::TabBar);
388}
389
390#if QT_CONFIG(accessibility)
391QAccessible::Role QQuickTabBar::accessibleRole() const
392{
393 return QAccessible::PageTabList;
394}
395#endif
396
397/*!
398 \qmlattachedproperty int QtQuick.Controls::TabBar::index
399 \since QtQuick.Controls 2.3 (Qt 5.10)
400 \readonly
401
402 This attached property holds the index of each tab button in the TabBar.
403
404 It is attached to each tab button of the TabBar.
405*/
406
407/*!
408 \qmlattachedproperty TabBar QtQuick.Controls::TabBar::tabBar
409 \since QtQuick.Controls 2.3 (Qt 5.10)
410 \readonly
411
412 This attached property holds the tab bar that manages this tab button.
413
414 It is attached to each tab button of the TabBar.
415*/
416
417/*!
418 \qmlattachedproperty enumeration QtQuick.Controls::TabBar::position
419 \since QtQuick.Controls 2.3 (Qt 5.10)
420 \readonly
421
422 This attached property holds the position of the tab bar.
423
424 It is attached to each tab button of the TabBar.
425
426 Possible values:
427 \value TabBar.Header The tab bar is at the top, as a window or page header.
428 \value TabBar.Footer The tab bar is at the bottom, as a window or page footer.
429*/
430
431void QQuickTabBarAttachedPrivate::update(QQuickTabBar *newTabBar, int newIndex)
432{
433 Q_Q(QQuickTabBarAttached);
434 const int oldIndex = index;
435 const QQuickTabBar *oldTabBar = tabBar;
436 const QQuickTabBar::Position oldPos = q->position();
437
438 index = newIndex;
439 tabBar = newTabBar;
440
441 if (oldTabBar != newTabBar) {
442 if (oldTabBar)
443 QObject::disconnect(oldTabBar, &QQuickTabBar::positionChanged, q, &QQuickTabBarAttached::positionChanged);
444 if (newTabBar)
445 QObject::connect(newTabBar, &QQuickTabBar::positionChanged, q, &QQuickTabBarAttached::positionChanged);
446 emit q->tabBarChanged();
447 }
448
449 if (oldIndex != newIndex)
450 emit q->indexChanged();
451 if (oldPos != q->position())
452 emit q->positionChanged();
453}
454
455QQuickTabBarAttached::QQuickTabBarAttached(QObject *parent)
456 : QObject(*(new QQuickTabBarAttachedPrivate), parent)
457{
458}
459
460int QQuickTabBarAttached::index() const
461{
462 Q_D(const QQuickTabBarAttached);
463 return d->index;
464}
465
466QQuickTabBar *QQuickTabBarAttached::tabBar() const
467{
468 Q_D(const QQuickTabBarAttached);
469 return d->tabBar;
470}
471
472QQuickTabBar::Position QQuickTabBarAttached::position() const
473{
474 Q_D(const QQuickTabBarAttached);
475 if (!d->tabBar)
476 return QQuickTabBar::Header;
477 return d->tabBar->position();
478}
479
480QT_END_NAMESPACE
481
482#include "moc_qquicktabbar_p.cpp"
Allows the user to switch between different views or subtasks.
void itemImplicitHeightChanged(QQuickItem *item) override
QPalette defaultPalette() const override
qreal getContentHeight() const override
void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override
void itemImplicitWidthChanged(QQuickItem *item) override
qreal getContentWidth() const override