Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qquickbuttongroup.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
5
#
include
"qquickbuttongroup_p.h"
6
7
#
include
<
QtCore
/
private
/
qobject_p
.
h
>
8
#
include
<
QtCore
/
qmetaobject
.
h
>
9
#
include
<
QtCore
/
qvariant
.
h
>
10
#
include
<
QtQml
/
qqmlinfo
.
h
>
11
12
#
include
"qquickabstractbutton_p_p.h"
13
14
QT_BEGIN_NAMESPACE
15
16
/*!
17
\qmltype ButtonGroup
18
\inherits QtObject
19
//! \nativetype QQuickButtonGroup
20
\inqmlmodule QtQuick.Controls
21
\since 5.7
22
\ingroup utilities
23
\brief Mutually-exclusive group of checkable buttons.
24
25
ButtonGroup is a non-visual, mutually exclusive group of buttons.
26
It is used with controls such as RadioButton, where only one of the options
27
can be selected at a time.
28
29
The most straight-forward way to use ButtonGroup is to assign
30
a list of buttons. For example, the list of children of a
31
\l{Item Positioners}{positioner} or a \l{Qt Quick Layouts}{layout}
32
that manages a group of mutually exclusive buttons.
33
34
\code
35
ButtonGroup {
36
buttons: column.children
37
}
38
39
Column {
40
id: column
41
42
RadioButton {
43
checked: true
44
text: qsTr("DAB")
45
}
46
47
RadioButton {
48
text: qsTr("FM")
49
}
50
51
RadioButton {
52
text: qsTr("AM")
53
}
54
}
55
\endcode
56
57
Mutually exclusive buttons do not always share the same parent item,
58
or the parent layout may sometimes contain items that should not be
59
included in the button group. Such cases are best handled using
60
the \l group attached property.
61
62
\code
63
ButtonGroup { id: radioGroup }
64
65
Column {
66
Label {
67
text: qsTr("Radio:")
68
}
69
70
RadioButton {
71
checked: true
72
text: qsTr("DAB")
73
ButtonGroup.group: radioGroup
74
}
75
76
RadioButton {
77
text: qsTr("FM")
78
ButtonGroup.group: radioGroup
79
}
80
81
RadioButton {
82
text: qsTr("AM")
83
ButtonGroup.group: radioGroup
84
}
85
}
86
\endcode
87
88
Another option is to filter the list of children. This is especially handy
89
if you're using a repeater to populate it, since the repeater will also be
90
a child of the parent layout:
91
92
\code
93
ButtonGroup {
94
buttons: column.children.filter((child) => child !== repeater)
95
}
96
97
Column {
98
id: column
99
100
Repeater {
101
id: repeater
102
model: [ qsTr("DAB"), qsTr("AM"), qsTr("FM") ]
103
RadioButton {
104
required property string modelData
105
text: modelData
106
}
107
}
108
}
109
\endcode
110
111
More advanced use cases can be handled using the \c addButton() and
112
\c removeButton() methods.
113
114
\sa RadioButton, {Button Controls}
115
*/
116
117
/*!
118
\qmlsignal QtQuick.Controls::ButtonGroup::clicked(AbstractButton button)
119
\since QtQuick.Controls 2.1 (Qt 5.8)
120
121
This signal is emitted when a \a button in the group has been clicked.
122
123
This signal is convenient for implementing a common signal handler for
124
all buttons in the same group.
125
126
\code
127
ButtonGroup {
128
buttons: column.children
129
onClicked: button => {
130
console.log("clicked:", button.text)
131
}
132
}
133
134
Column {
135
id: column
136
Button { text: "First" }
137
Button { text: "Second" }
138
Button { text: "Third" }
139
}
140
\endcode
141
142
\sa AbstractButton::clicked()
143
*/
144
145
class
QQuickButtonGroupPrivate
:
public
QObjectPrivate
146
{
147
public
:
148
Q_DECLARE_PUBLIC(QQuickButtonGroup)
149
150
void
clear
();
151
void
buttonClicked
();
152
void
_q_updateCurrent
();
153
void
updateCheckState
();
154
void
setCheckState
(Qt::CheckState state);
155
156
static
void
buttons_append
(QQmlListProperty<QQuickAbstractButton> *prop, QQuickAbstractButton *obj);
157
static
qsizetype
buttons_count
(QQmlListProperty<QQuickAbstractButton> *prop);
158
static
QQuickAbstractButton *
buttons_at
(QQmlListProperty<QQuickAbstractButton> *prop, qsizetype index);
159
static
void
buttons_clear
(QQmlListProperty<QQuickAbstractButton> *prop);
160
161
bool
complete
=
true
;
162
bool
exclusive
=
true
;
163
bool
settingCheckState
=
false
;
164
Qt
::
CheckState
checkState
=
Qt
::
Unchecked
;
165
QPointer
<
QQuickAbstractButton
>
checkedButton
;
166
QList
<
QQuickAbstractButton
*>
buttons
;
167
};
168
169
void
QQuickButtonGroupPrivate
::
clear
()
170
{
171
for
(QQuickAbstractButton *button : std::as_const(buttons)) {
172
auto
*attached = qobject_cast<QQuickButtonGroupAttached *>(
173
qmlAttachedPropertiesObject<QQuickButtonGroup>(button,
false
));
174
if
(attached) {
175
attached->setGroup(
nullptr
);
176
}
else
{
177
QQuickAbstractButtonPrivate::get(button)->group =
nullptr
;
178
QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked,
this
, &QQuickButtonGroupPrivate::buttonClicked);
179
QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged,
this
, &QQuickButtonGroupPrivate::_q_updateCurrent);
180
}
181
}
182
buttons.clear();
183
}
184
185
void
QQuickButtonGroupPrivate
::
buttonClicked
()
186
{
187
Q_Q(QQuickButtonGroup);
188
QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
189
if
(button)
190
emit q->clicked(button);
191
}
192
193
void
QQuickButtonGroupPrivate
::
_q_updateCurrent
()
194
{
195
Q_Q(QQuickButtonGroup);
196
if
(
exclusive
) {
197
QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
198
if
(button && button->isChecked())
199
q->setCheckedButton(button);
200
else
if
(!buttons.contains(checkedButton))
201
q->setCheckedButton(
nullptr
);
202
}
203
updateCheckState
(
)
;
204
}
205
206
void
QQuickButtonGroupPrivate
::
updateCheckState
()
207
{
208
if
(!
complete
||
settingCheckState
)
209
return
;
210
211
bool
anyChecked =
false
;
212
bool
allChecked = !buttons.isEmpty();
213
for
(QQuickAbstractButton *button : std::as_const(buttons)) {
214
const
bool
isChecked = button->isChecked();
215
anyChecked |= isChecked;
216
allChecked &= isChecked;
217
}
218
setCheckState(Qt::CheckState(anyChecked + allChecked));
219
}
220
221
void
QQuickButtonGroupPrivate
::
setCheckState
(Qt::CheckState state)
222
{
223
Q_Q(QQuickButtonGroup);
224
if
(checkState == state)
225
return
;
226
227
checkState = state;
228
emit q->checkStateChanged();
229
}
230
231
void
QQuickButtonGroupPrivate
::buttons_append(QQmlListProperty<QQuickAbstractButton> *prop, QQuickAbstractButton *obj)
232
{
233
QQuickButtonGroup *q =
static_cast
<QQuickButtonGroup *>(prop->object);
234
q->addButton(obj);
235
}
236
237
qsizetype
QQuickButtonGroupPrivate
::buttons_count(QQmlListProperty<QQuickAbstractButton> *prop)
238
{
239
QQuickButtonGroupPrivate
*p =
static_cast
<
QQuickButtonGroupPrivate
*>(prop->data);
240
return
p->buttons.size();
241
}
242
243
QQuickAbstractButton *
QQuickButtonGroupPrivate
::buttons_at(QQmlListProperty<QQuickAbstractButton> *prop, qsizetype index)
244
{
245
QQuickButtonGroupPrivate
*p =
static_cast
<
QQuickButtonGroupPrivate
*>(prop->data);
246
return
p->buttons.value(index);
247
}
248
249
void
QQuickButtonGroupPrivate
::buttons_clear(QQmlListProperty<QQuickAbstractButton> *prop)
250
{
251
QQuickButtonGroupPrivate
*p =
static_cast
<
QQuickButtonGroupPrivate
*>(prop->data);
252
if
(!p->buttons.isEmpty()) {
253
p
->
clear
(
)
;
254
QQuickButtonGroup *q =
static_cast
<QQuickButtonGroup *>(prop->object);
255
// QTBUG-52358: don't clear the checked button immediately
256
QMetaObject::invokeMethod(q,
"_q_updateCurrent"
, Qt::QueuedConnection);
257
emit q->buttonsChanged();
258
}
259
}
260
261
QQuickButtonGroup::QQuickButtonGroup(QObject *parent)
262
: QObject(*(
new
QQuickButtonGroupPrivate), parent)
263
{
264
}
265
266
QQuickButtonGroup::~QQuickButtonGroup()
267
{
268
Q_D(QQuickButtonGroup);
269
d->clear();
270
}
271
272
QQuickButtonGroupAttached *QQuickButtonGroup::qmlAttachedProperties(QObject *object)
273
{
274
return
new
QQuickButtonGroupAttached(object);
275
}
276
277
/*!
278
\qmlproperty AbstractButton QtQuick.Controls::ButtonGroup::checkedButton
279
280
This property holds the currently selected button in an exclusive group,
281
or \c null if there is none or the group is non-exclusive.
282
283
By default, it is the first checked button added to an exclusive button group.
284
285
\sa exclusive
286
*/
287
QQuickAbstractButton *QQuickButtonGroup::checkedButton()
const
288
{
289
Q_D(
const
QQuickButtonGroup);
290
return
d->checkedButton;
291
}
292
293
void
QQuickButtonGroup::setCheckedButton(QQuickAbstractButton *checkedButton)
294
{
295
Q_D(QQuickButtonGroup);
296
if
(d->checkedButton == checkedButton)
297
return
;
298
299
if
(d->checkedButton)
300
d->checkedButton->setChecked(
false
);
301
d->checkedButton = checkedButton;
302
if
(checkedButton)
303
checkedButton->setChecked(
true
);
304
emit checkedButtonChanged();
305
}
306
307
/*!
308
\qmlproperty list<AbstractButton> QtQuick.Controls::ButtonGroup::buttons
309
310
This property holds the list of buttons.
311
312
\code
313
ButtonGroup {
314
buttons: column.children
315
}
316
317
Column {
318
id: column
319
320
RadioButton {
321
checked: true
322
text: qsTr("Option A")
323
}
324
325
RadioButton {
326
text: qsTr("Option B")
327
}
328
}
329
\endcode
330
331
\sa group
332
*/
333
QQmlListProperty<QQuickAbstractButton> QQuickButtonGroup::buttons()
334
{
335
Q_D(QQuickButtonGroup);
336
return
QQmlListProperty<QQuickAbstractButton>(
this
, d,
337
QQuickButtonGroupPrivate::buttons_append,
338
QQuickButtonGroupPrivate::buttons_count,
339
QQuickButtonGroupPrivate::buttons_at,
340
QQuickButtonGroupPrivate::buttons_clear);
341
}
342
343
/*!
344
\since QtQuick.Controls 2.3 (Qt 5.10)
345
\qmlproperty bool QtQuick.Controls::ButtonGroup::exclusive
346
347
This property holds whether the button group is exclusive. The default value is \c true.
348
349
If this property is \c true, then only one button in the group can be checked at any given time.
350
The user can click on any button to check it, and that button will replace the existing one as
351
the checked button in the group.
352
353
In an exclusive group, the user cannot uncheck the currently checked button by clicking on it;
354
instead, another button in the group must be clicked to set the new checked button for that group.
355
356
In a non-exclusive group, checking and unchecking buttons does not affect the other buttons in
357
the group. Furthermore, the value of the \l checkedButton property is \c null.
358
*/
359
bool
QQuickButtonGroup::isExclusive()
const
360
{
361
Q_D(
const
QQuickButtonGroup);
362
return
d->exclusive;
363
}
364
365
void
QQuickButtonGroup::setExclusive(
bool
exclusive)
366
{
367
Q_D(QQuickButtonGroup);
368
if
(d->exclusive == exclusive)
369
return
;
370
371
d->exclusive = exclusive;
372
emit exclusiveChanged();
373
}
374
375
/*!
376
\since QtQuick.Controls 2.4 (Qt 5.11)
377
\qmlproperty enumeration QtQuick.Controls::ButtonGroup::checkState
378
379
This property holds the combined check state of the button group.
380
381
Available states:
382
\value Qt.Unchecked None of the buttons are checked.
383
\value Qt.PartiallyChecked Some of the buttons are checked.
384
\value Qt.Checked All of the buttons are checked.
385
386
Setting the check state of a non-exclusive button group to \c Qt.Unchecked
387
or \c Qt.Checked unchecks or checks all buttons in the group, respectively.
388
\c Qt.PartiallyChecked is ignored.
389
390
Setting the check state of an exclusive button group to \c Qt.Unchecked
391
unchecks the \l checkedButton. \c Qt.Checked and \c Qt.PartiallyChecked
392
are ignored.
393
*/
394
Qt::CheckState QQuickButtonGroup::checkState()
const
395
{
396
Q_D(
const
QQuickButtonGroup);
397
return
d->checkState;
398
}
399
400
void
QQuickButtonGroup::setCheckState(Qt::CheckState state)
401
{
402
Q_D(QQuickButtonGroup);
403
if
(d->checkState == state || state == Qt::PartiallyChecked)
404
return
;
405
406
d->settingCheckState =
true
;
407
if
(d->exclusive) {
408
if
(d->checkedButton && state == Qt::Unchecked)
409
setCheckedButton(
nullptr
);
410
}
else
{
411
for
(QQuickAbstractButton *button : std::as_const(d->buttons))
412
button->setChecked(state == Qt::Checked);
413
}
414
d->settingCheckState =
false
;
415
d->setCheckState(state);
416
}
417
418
/*!
419
\qmlmethod void QtQuick.Controls::ButtonGroup::addButton(AbstractButton button)
420
421
Adds a \a button to the button group.
422
423
\note Manually adding objects to a button group is typically unnecessary.
424
The \l buttons property and the \l group attached property provide a
425
convenient and declarative syntax.
426
427
\sa buttons, group
428
*/
429
void
QQuickButtonGroup::addButton(QQuickAbstractButton *button)
430
{
431
Q_D(QQuickButtonGroup);
432
if
(!button || d->buttons.contains(button))
433
return
;
434
435
QQuickAbstractButtonPrivate::get(button)->group =
this
;
436
QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
437
QObjectPrivate::connect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
438
439
if
(d->exclusive && button->isChecked())
440
setCheckedButton(button);
441
442
d->buttons.append(button);
443
d->updateCheckState();
444
emit buttonsChanged();
445
}
446
447
/*!
448
\qmlmethod void QtQuick.Controls::ButtonGroup::removeButton(AbstractButton button)
449
450
Removes a \a button from the button group.
451
452
\note Manually removing objects from a button group is typically unnecessary.
453
The \l buttons property and the \l group attached property provide a
454
convenient and declarative syntax.
455
456
\sa buttons, group
457
*/
458
void
QQuickButtonGroup::removeButton(QQuickAbstractButton *button)
459
{
460
Q_D(QQuickButtonGroup);
461
if
(!button || !d->buttons.contains(button))
462
return
;
463
464
QQuickAbstractButtonPrivate::get(button)->group =
nullptr
;
465
QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
466
QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
467
468
if
(d->checkedButton == button)
469
setCheckedButton(
nullptr
);
470
471
d->buttons.removeOne(button);
472
d->updateCheckState();
473
emit buttonsChanged();
474
}
475
476
void
QQuickButtonGroup::classBegin()
477
{
478
Q_D(QQuickButtonGroup);
479
d->complete =
false
;
480
}
481
482
void
QQuickButtonGroup::componentComplete()
483
{
484
Q_D(QQuickButtonGroup);
485
d->complete =
true
;
486
if
(!d->buttons.isEmpty())
487
d->updateCheckState();
488
}
489
490
class
QQuickButtonGroupAttachedPrivate
:
public
QObjectPrivate
491
{
492
public
:
493
QQuickButtonGroup *
group
=
nullptr
;
494
};
495
496
QQuickButtonGroupAttached::QQuickButtonGroupAttached(QObject *parent)
497
: QObject(*(
new
QQuickButtonGroupAttachedPrivate), parent)
498
{
499
}
500
501
/*!
502
\qmlattachedproperty ButtonGroup QtQuick.Controls::ButtonGroup::group
503
504
This property attaches a button to a button group.
505
506
\code
507
ButtonGroup { id: group }
508
509
RadioButton {
510
checked: true
511
text: qsTr("Option A")
512
ButtonGroup.group: group
513
}
514
515
RadioButton {
516
text: qsTr("Option B")
517
ButtonGroup.group: group
518
}
519
\endcode
520
521
\sa buttons
522
*/
523
QQuickButtonGroup *QQuickButtonGroupAttached::group()
const
524
{
525
Q_D(
const
QQuickButtonGroupAttached);
526
return
d->group;
527
}
528
529
void
QQuickButtonGroupAttached::setGroup(QQuickButtonGroup *group)
530
{
531
Q_D(QQuickButtonGroupAttached);
532
if
(d->group == group)
533
return
;
534
535
auto
*button = qobject_cast<QQuickAbstractButton *>(parent());
536
if
(d->group)
537
d->group->removeButton(button);
538
d->group = group;
539
if
(group)
540
group->addButton(button);
541
emit groupChanged();
542
}
543
544
QT_END_NAMESPACE
545
546
#
include
"moc_qquickbuttongroup_p.cpp"
QQuickButtonGroupAttachedPrivate
Definition
qquickbuttongroup.cpp:491
QQuickButtonGroupAttachedPrivate::group
QQuickButtonGroup * group
Definition
qquickbuttongroup.cpp:493
QQuickButtonGroupPrivate
Mutually-exclusive group of checkable buttons.
Definition
qquickbuttongroup.cpp:146
QQuickButtonGroupPrivate::buttons_at
static QQuickAbstractButton * buttons_at(QQmlListProperty< QQuickAbstractButton > *prop, qsizetype index)
Definition
qquickbuttongroup.cpp:243
QQuickButtonGroupPrivate::setCheckState
void setCheckState(Qt::CheckState state)
Definition
qquickbuttongroup.cpp:221
QQuickButtonGroupPrivate::buttons
QList< QQuickAbstractButton * > buttons
Definition
qquickbuttongroup.cpp:166
QQuickButtonGroupPrivate::buttons_count
static qsizetype buttons_count(QQmlListProperty< QQuickAbstractButton > *prop)
Definition
qquickbuttongroup.cpp:237
QQuickButtonGroupPrivate::exclusive
bool exclusive
Definition
qquickbuttongroup.cpp:162
QQuickButtonGroupPrivate::checkState
Qt::CheckState checkState
Definition
qquickbuttongroup.cpp:164
QQuickButtonGroupPrivate::settingCheckState
bool settingCheckState
Definition
qquickbuttongroup.cpp:163
QQuickButtonGroupPrivate::checkedButton
QPointer< QQuickAbstractButton > checkedButton
Definition
qquickbuttongroup.cpp:165
QQuickButtonGroupPrivate::_q_updateCurrent
void _q_updateCurrent()
Definition
qquickbuttongroup.cpp:193
QQuickButtonGroupPrivate::buttons_clear
static void buttons_clear(QQmlListProperty< QQuickAbstractButton > *prop)
Definition
qquickbuttongroup.cpp:249
QQuickButtonGroupPrivate::clear
void clear()
Definition
qquickbuttongroup.cpp:169
QQuickButtonGroupPrivate::updateCheckState
void updateCheckState()
Definition
qquickbuttongroup.cpp:206
QQuickButtonGroupPrivate::buttonClicked
void buttonClicked()
Definition
qquickbuttongroup.cpp:185
QQuickButtonGroupPrivate::buttons_append
static void buttons_append(QQmlListProperty< QQuickAbstractButton > *prop, QQuickAbstractButton *obj)
Definition
qquickbuttongroup.cpp:231
QQuickButtonGroupPrivate::complete
bool complete
Definition
qquickbuttongroup.cpp:161
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qtdeclarative
src
quicktemplates
qquickbuttongroup.cpp
Generated on
for Qt by
1.18.0