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