Всех приветствую, сегодня продолжим обзор наиболее базовых элементов QML - на очереди стоит CheckBox. И снова большинство вопросов связаны с кастомизацией стиля, поэтому обязательно рассмотрим пару-тройку конкретных вариантов реализации.
QML CheckBox. Базовые операции.
Начнем по традиции с пустого Qt Quick проекта, в который добавим исключительно то, что будем рассматривать, то есть CheckBox посередине окна 👍

Все изменения сегодня будут осуществлены в main.qml:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
CheckBox {
id: testCheckBox
anchors.centerIn: parent
text: qsTr("To check or not to check...")
}
}
В принципе, обычно взаимодействие с CheckBox заключается в проверке свойства checkState. Возможные значения зависят в свою очередь от свойства tristate. По умолчанию tristate = false, и checkState может принимать значения:
- Qt.Unchecked
- Qt.Checked
Если tristate = true, то спектр вариантов пополняется еще одним:
- Qt.Unchecked
- Qt.PartiallyChecked
- Qt.Checked
Тут все просто и очевидно, но тем не менее небольшой пример. Добавим текстовое поле под CheckBox для отображения его состояния:
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
CheckBox {
id: testCheckBox
anchors.centerIn: parent
text: qsTr("To check or not to check...")
onCheckStateChanged: {
switch (checkState) {
case Qt.Unchecked:
testCheckBoxState.text = "I'm unchecked";
break;
case Qt.PartiallyChecked:
testCheckBoxState.text = "I'm partially checked";
break;
case Qt.Checked:
testCheckBoxState.text = "I'm checked";
break;
default:
break;
}
}
}
Text {
id: testCheckBoxState
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: testCheckBox.bottom
anchors.topMargin: 10
text: qsTr("State")
}
}

Об изменении checkState мы узнаем из обработчика onCheckStateChanged. Без него мы могли спокойно обойтись, просто забросив в Text:
Text {
id: testCheckBoxState
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: testCheckBox.bottom
anchors.topMargin: 10
text: qsTr("State") + " " + testCheckBox.checkState
}
Но ладно, оставим обработчик и изменим tristate:
CheckBox {
id: testCheckBox
anchors.centerIn: parent
tristate: true
// ...............
Результат закономерен:

По сути это скорее справочная информация, поскольку все максимально просто. Так что рассмотрим еще один, менее распространенный, но тем не менее часто использующийся вариант, который, в общем-то, неплохо разобран и в официальной документации.
QML CheckBox. Иерархическая структура.
Кстати здесь будет уже понятно, зачем вообще нужно состояние Qt.PartiallyChecked. Итак, добавим три CheckBox и элемент ButtonGroup. При этом свяжем их друг с другом при помощи свойства ButtonGroup.group каждого из CheckBox:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
Column {
id: mainColumn
ButtonGroup {
id: primaryGroup
exclusive: false
}
CheckBox {
text: qsTr("CheckBox 1")
ButtonGroup.group: primaryGroup
}
CheckBox {
text: qsTr("CheckBox 2")
ButtonGroup.group: primaryGroup
}
CheckBox {
text: qsTr("CheckBox 3")
ButtonGroup.group: primaryGroup
}
}
Text {
id: primaryGroupState
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: mainColumn.bottom
anchors.topMargin: 10
text: qsTr("State") + " " + primaryGroup.checkState
}
}
В Text будем выводить состояние ButtonGroup через primaryGroup.checkState. В чем смысл содеянного... А смысл в том, что состояние ButtonGroup будет определяться состояниями всех, добавленных к ней элементов. То есть в данном случае это CheckBox'ы. При этом взаимосвязь следующая:
- Если все CheckBox - unchecked, то и primaryGroup - unchecked.
- Если все CheckBox - checked, то primaryGroup - checked.
- Если часть из CheckBox (но не все) - checked, primaryGroup - partially checked.
Вот такая логика. Проверяем:

Помним, что Qt.Unchecked соответствует 0, Qt.PartiallyChecked - 1, Qt.Checked - 2. На базе этого можно построить иерархическую структуру CheckBox'ов. Суть заключается в том, что добавляется некий "главный" CheckBox, и его состояние жестко связывается с состоянием ButtonGroup. При этом текущие три CheckBox'а свойством leftPadding немного смещаются правее, что визуально выглядит как некая иерархия:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
Column {
id: mainColumn
CheckBox {
id: mainCheckBox
text: qsTr("Main")
checkState: primaryGroup.checkState
}
ButtonGroup {
id: primaryGroup
exclusive: false
checkState: mainCheckBox.checkState
}
CheckBox {
text: qsTr("CheckBox 1")
leftPadding: 20
ButtonGroup.group: primaryGroup
}
CheckBox {
text: qsTr("CheckBox 2")
leftPadding: 20
ButtonGroup.group: primaryGroup
}
CheckBox {
text: qsTr("CheckBox 3")
leftPadding: 20
ButtonGroup.group: primaryGroup
}
}
Text {
id: primaryGroupState
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: mainColumn.bottom
anchors.topMargin: 10
text: qsTr("State") + " " + primaryGroup.checkState
}
}
Ну и, естественно, состояние mainCheckBox теперь меняется так же, как ранее мы разбирали для ButtonGroup. Результат получаем такой:
По аналогии можно сделать и трехуровневый список:
Код же будет такой:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
Column {
id: mainColumn
CheckBox {
id: mainCheckBox
text: qsTr("Main")
checkState: primaryGroup.checkState
}
ButtonGroup {
id: primaryGroup
exclusive: false
checkState: mainCheckBox.checkState
}
CheckBox {
text: qsTr("CheckBox 1")
leftPadding: 20
ButtonGroup.group: primaryGroup
}
CheckBox {
text: qsTr("CheckBox 2")
leftPadding: 20
ButtonGroup.group: primaryGroup
}
CheckBox {
id: checkBox3
text: qsTr("CheckBox 3")
leftPadding: 20
ButtonGroup.group: primaryGroup
checkState: secondaryGroup.checkState
}
ButtonGroup {
id: secondaryGroup
exclusive: false
checkState: checkBox3.checkState
}
CheckBox {
text: qsTr("CheckBox 3.1")
leftPadding: 40
ButtonGroup.group: secondaryGroup
}
CheckBox {
text: qsTr("CheckBox 3.2")
leftPadding: 40
ButtonGroup.group: secondaryGroup
}
}
}
Все, переходим к следующему подразделу.
QML CheckBox. Стили. Кастомизация.
Опять же, как и для многих QML компонентов, можно легко выделить несколько конкретных свойств, отвечающих за ту или иную часть CheckBox'а. В данном случае их три:
- background
- contentItem
- indicator
Откатимся снова к первоначальному виду приложения и рассмотрим несколько вариантов кастомизации стиля на основе перечисленных свойств. На конкретных примерах будет более понятно, что и за что отвечает:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
CheckBox {
id: testCheckBox
anchors.centerIn: parent
text: qsTr("To check or not to check...")
background: Rectangle {
color: "#C0C0C0"
}
contentItem: Text {
color: "#800000";
text: testCheckBox.text
verticalAlignment: Text.AlignVCenter
leftPadding: testCheckBox.indicator.width
}
indicator: Rectangle {
color: testCheckBox.checked ? "#2E8B57" : "#3CB371"
y: testCheckBox.height / 2 - height / 2
implicitWidth: 25
implicitHeight: 25
}
}
}

Дизайн, очевидно, так себе ) Но тут смысл в том, чтобы разобраться, за что отвечают те или иные свойства и под себя уже сделать как душе угодно. Для indicator можно добавить еще внутренний элемент, к примеру так:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
CheckBox {
id: testCheckBox
anchors.centerIn: parent
text: qsTr("To check or not to check...")
background: Rectangle {
color: "transparent"
}
contentItem: Text {
color: "#000000";
text: testCheckBox.text
verticalAlignment: Text.AlignVCenter
leftPadding: testCheckBox.indicator.width
}
indicator: Rectangle {
color: "#008080"
y: testCheckBox.height / 2 - height / 2
implicitWidth: 25
implicitHeight: 25
radius: 8
Rectangle {
color: "#E0FFFF"
visible: testCheckBox.checked
width: parent.width / 2
height: parent.height / 2
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
radius: 4
}
}
}
}

Ну и еще вариант, на базе предыдущего:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
width: 320
height: 240
visible: true
title: qsTr("QML CheckBox Review ")
color: "#303035"
CheckBox {
id: testCheckBox
anchors.centerIn: parent
text: qsTr("To check or not to check...")
background: Rectangle {
color: "transparent"
}
contentItem: Text {
color: "#FFFFFF";
text: testCheckBox.text
verticalAlignment: Text.AlignVCenter
leftPadding: testCheckBox.indicator.width
font.pointSize: 9
}
indicator: Rectangle {
y: testCheckBox.height / 2 - height / 2
implicitWidth: 25
implicitHeight: 25
radius: 4
border.color: "#800000"
Rectangle {
visible: testCheckBox.checked
width: parent.width / 2
height: parent.height / 2
x: parent.width / 2 - width / 2
y: parent.height / 2 - height / 2
radius: 2
color: testCheckBox.down ? "#CD5C5C" : "#B22222"
}
}
}
}

На этом заканчиваем сегодняшний обзор CheckBox, до связи!



