Всех приветствую, сегодня продолжим обзор наиболее базовых элементов 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
, до связи!