Делегаты форм на страницах параметров
Kirigami Addons — это дополнительный набор визуальных компонентов, которые хорошо работают на мобильных устройствах и настольных компьютерах и гарантированно являются кроссплатформенными. Для создания компонентов используется Kirigami.
Теперь, когда в приложение добавлены страницы About и AboutKDE, те же внутренние компоненты позволяют создавать страницы параметров.
Структура проекта должна выглядеть так:
addonsexample
├── CMakeLists.txt
├── main.cpp
├── Main.qml
├── MyAboutPage.qml
└── SettingsPage.qmlТребуемые изменения
Измените Main.qml, чтобы добавить новую страницу параметров:
import QtQuick
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.about 1.0
Kirigami.ApplicationWindow {
id: root
width: 600
height: 700
Component {
id: aboutkde
FormCard.AboutKDE {}
}
Component {
id: aboutpage
MyAboutPage {}
}
Component {
id: settingspage
SettingsPage {}
}
pageStack.initialPage: Kirigami.ScrollablePage {
ColumnLayout {
FormCard.FormCard {
FormCard.FormButtonDelegate {
id: aboutKDEButton
icon.name: "kde"
text: i18n("About KDE Page")
onClicked: root.pageStack.layers.push(aboutkde)
}
FormCard.FormButtonDelegate {
id: aboutPageButton
icon.name: "applications-utilities"
text: i18n("About Addons Example")
onClicked: root.pageStack.layers.push(aboutpage)
}
FormCard.FormButtonDelegate {
id: settingsButton
icon.name: "settings-configure"
text: i18n("Single Settings Page")
onClicked: root.pageStack.layers.push(settingspage)
}
}
}
}
}Теперь можно приступить к рассмотрению компонентов, из которых создаётся страница параметров: FormCard и его делегаты.
Делегаты форм
FormCard и FormCardPage
FormCard.FormCard — основной компонент, который будет использоваться для группировки всех его дочерних компонентов — делегатов.
Ранее карточка формы использовалась во введении в Kirigami Addons. Её основное назначение — служить контейнером для других компонентов, при этом цвет карточки отличается от цвета фона, как у Kirigami.Card.
Создайте новый файл SettingsPage.qml:
import QtQuick
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormCard {
// Здесь размещаются все делегаты!
}
FormCard.FormCard {
// Здесь размещаются все делегаты!
}
}Так как для страницы параметров создаётся отдельный файл QML и нужно предусмотреть возможную прокрутку страницы, используется FormCard.FormCardPage, который наследуется от Kirigami.ScrollablePage.
Преимущество страницы карточки формы в том, что она имеет встроенную компоновку, поэтому дополнительный ColumnLayout не нужен, а делегаты добавляются непосредственно в неё.
Примечание
Делегаты FormCard можно использовать напрямую с Kirigami.ScrollablePage, но в этом случае потребуется добавить собственные компоновки.FormHeader
Для каждой создаваемой FormCard можно создать FormHeader непосредственно перед ней. Заголовок использует полужирное начертание и показывается прямо над карточкой формы.
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormHeader {
title: i18n("General")
}
FormCard.FormCard {
// Здесь размещаются делегаты…
}
FormCard.FormHeader {
title: i18n("Accounts")
}
FormCard.FormCard {
// Здесь размещаются делегаты…
}
}FormTextDelegate и FormSectionText
Начнём с простого — с обычного текста.
FormSectionText просто добавляет тонкий делегат, содержащий надпись. FormTextDelegate содержит текст и серое описание.
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormHeader {
title: i18n("General")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: i18n("Current Color Scheme")
description: "Breeze"
}
}
FormCard.FormHeader {
title: i18n("Accounts")
}
FormCard.FormCard {
FormCard.FormSectionText {
text: i18n("Online Account Settings")
}
FormCard.FormTextDelegate {
leading: Kirigami.Icon {source: "user"}
text: "John Doe"
description: i18n("The Maintainer ™️")
}
}
}Добавляется фиктивный текст для гипотетического определения оформления. Если потребуется настоящее определение цветовой схемы, в будущем это можно сделать по аналогии с Neochat (код здесь), используя модель C++ с KColorSchemeManager.
В разделе «Учётные записи в Интернете» имеется дополнительное свойство leading. К нему можно добавить Item, чтобы он показывался перед текстом. Противоположное свойство trailing позволяет показать Item после текста, но в приложении оно не используется.
Для простоты здесь используется Kirigami.Icon, но это можно также реализовать с помощью Avatar из Kirigami Addons, который получает информацию из модели, как это сделано в Neochat.
В итоге должно получиться так:

FormButtonDelegate
FormButtonDelegate внешне похож на FormTextDelegate, но по нему можно щёлкнуть, и он показывает стрелку, направленную вправо. Ранее он использовался во введении в Kirigami Addons.
В отличие от FormTextDelegate, у которого были свойства leading и trailing для показа элемента до и после основного содержимого, FormButtonDelegate имеет только свойство leading, так как правая сторона занята стрелкой.
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormHeader {
title: i18n("General")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: i18n("Current Color Scheme")
description: "Breeze"
}
}
FormCard.FormHeader {
title: i18n("Accounts")
}
FormCard.FormCard {
FormCard.FormSectionText {
text: i18n("Online Account Settings")
}
FormCard.FormTextDelegate {
leading: Kirigami.Icon {source: "user"}
text: "John Doe"
description: i18n("The Maintainer ™️")
}
FormCard.FormButtonDelegate {
icon.name: "list-add"
text: i18n("Add a new account")
onClicked: console.info("Clicked!")
}
}
}Свойство icon.name используется, чтобы задать значок «плюс» (+), который показывается после места, где показывался бы leading, и перед основным содержимым. Это распространённый приём, указывающий на то, что кнопка добавит что-то в список.
Поскольку этот пример приводится лишь для наглядности, подробно не рассматривается, что произойдёт после нажатия кнопки: она просто выводит в терминал «Clicked!». Можно было бы создать новую страницу создания учётной записи, которая добавляет ещё одного пользователя в модель, а затем вывести страницу на экран — так же, как это сделано в Main.qml.

FormRadioDelegate, FormCheckDelegate и FormSwitchDelegate
Радиокнопки, флажки и переключатели — очень часто используемые компоненты любого пользовательского интерфейса. Kirigami Addons предоставляет их в виде FormRadioDelegate, FormCheckDelegate и FormSwitchDelegate.
Их единственные основные свойства — text и description. Различаются они по применению, поскольку все наследуются от AbstractButton, поэтому используются его сигналы и обработчики: checked и onChecked, toggled и onToggled, clicked и onClicked.
В приложении требуется реализовать функцию автосохранения, причём её параметры должны показываться, только если эта функция включена. Создайте новый раздел с помощью FormCard и FormHeader, затем добавьте FormSwitchDelegate и FormRadioDelegate.
FormCard.FormHeader {
title: i18n("Autosave")
}
FormCard.FormCard {
FormCard.FormSwitchDelegate {
id: autosave
text: i18n("Enabled")
}
FormCard.FormRadioDelegate {
text: i18n("After every change")
visible: autosave.checked
}
FormCard.FormRadioDelegate {
text: i18n("Every 10 minutes")
visible: autosave.checked
}
FormCard.FormRadioDelegate {
text: i18n("Every 30 minutes")
visible: autosave.checked
}
}Видимость каждой радиокнопки привязывается к переключателю, поэтому они показываются только тогда, когда переключатель включён.
Практические рекомендации
Нажмите, чтобы узнать больше
Если есть опыт программирования на императивных языках, таких как C++, может возникнуть соблазн установить свойство checked переключателя, чтобы включить видимость радиокнопок, присвоив true с помощью JavaScript, например:
checked: {
radio1.visible = true;
radio2.visible = true;
radio3.visible = true;
}Это не очень эффективно для декларативного языка QML, его сигналов и слотов. Вместо выражений JavaScript старайтесь по возможности использовать привязки QML, как в случае visible: autosave.checked.
Подробнее см. на этой странице.

Чтобы проверить флажок, можно добавить новый FormCheckDelegate в раздел «Общие».
FormCard.FormHeader {
title: i18n("General")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: i18n("Current Color Scheme")
description: "Breeze"
}
FormCard.FormCheckDelegate {
text: i18n("Show Tray Icon")
onToggled: {
if (checkState) {
console.info("A tray icon appears on your system!")
} else {
console.info("The tray icon disappears!")
}
}
}
}Здесь для показа фиктивного текста, имитирующего появление значка в системном лотке, используется обработчик сигнала onToggled. При желании значок в системном лотке можно легко реализовать с помощью KStatusNotifierItem из KDE или SystemTrayIcon из Qt.
Пока что наше приложение должно выглядеть так:

FormComboBoxDelegate
Обычный компонент ComboBox можно создать с помощью FormComboBoxDelegate.
У этого поля со списком есть несколько полезных свойств, которые можно использовать: editable, displayText и displayMode.
Установка editable: true позволяет редактировать текст поля со списком, что полезно, если нужно добавить новые варианты в поле со списком:

Если нужно показать дополнительный текст перед каждым параметром, можно использовать что-то вроде displayText: "Profile: " + currentText:

А самый интересный из них, который будет использоваться в примере, — displayMode. Он может принимать три значения:
- FormComboBoxDelegate.ComboBox: стандартный небольшой раскрывающийся список, показывающий перечень параметров.

- FormComboBoxDelegate.Dialog: диалог со списком параметров в середине окна, подобное Kirigami.OverlaySheet.

- FormComboBoxDelegate.Page: новая страница, содержащая список параметров, которые показываются в отдельном окне.

Добавьте следующий код между делегатами «Current Color Scheme» и «Show Tray Icon» в карточке формы «General».
FormCard.FormComboBoxDelegate {
text: i18n("Default Profile")
description: i18n("The profile to be loaded by default.")
displayMode: FormCard.FormComboBoxDelegate.ComboBox
currentIndex: 0
editable: false
model: ["Work", "Personal"]
}С флажком страница параметров должна выглядеть так:

FormDelegateSeparator
Страница параметров приобретает форму, но разделы становятся всё длиннее. Можно добавить несколько экземпляров FormDelegateSeparator, чтобы страница выглядела аккуратнее:
import QtQuick
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
id: root
title: i18nc("@title", "Settings")
FormCard.FormHeader {
title: i18nc("@title:group", "General")
}
FormCard.FormCard {
FormCard.FormTextDelegate {
text: i18nc("@info", "Current Color Scheme")
description: "Breeze"
}
FormCard.FormComboBoxDelegate {
id: combobox
text: i18nc("@label:listbox", "Default Profile")
description: i18nc("@info:whatsthis", "The profile to be loaded by default.")
displayMode: FormCard.FormComboBoxDelegate.ComboBox
currentIndex: 0
editable: false
model: ["Work", "Personal"]
}
FormCard.FormDelegateSeparator {
above: combobox
below: checkbox
}
FormCard.FormCheckDelegate {
id: checkbox
text: i18nc("@option:check", "Show Tray Icon")
onToggled: {
if (checkState) {
console.info("A tray icon appears on your system!")
} else {
console.info("The tray icon disappears!")
}
}
}
}
FormCard.FormHeader {
title: i18nc("@title:group", "Autosave")
}
FormCard.FormCard {
FormCard.FormSwitchDelegate {
id: autosave
text: i18nc("@option:check", "Enabled")
}
FormCard.FormDelegateSeparator {
above: autosave
below: firstradio
visible: autosave.checked
}
FormCard.FormRadioDelegate {
id: firstradio
text: i18nc("@option:radio", "After every change")
visible: autosave.checked
}
FormCard.FormRadioDelegate {
text: i18nc("@option:radio", "Every 10 minutes")
visible: autosave.checked
}
FormCard.FormRadioDelegate {
text: i18nc("@option:radio", "Every 30 minutes")
visible: autosave.checked
}
}
FormCard.FormHeader {
title: i18nc("@title:group", "Accounts")
}
FormCard.FormCard {
FormCard.FormSectionText {
text: i18nc("@info:whatsthis", "Online Account Settings")
}
FormCard.FormTextDelegate {
id: lastaccount
leading: Kirigami.Icon {source: "user"}
text: "John Doe"
description: i18nc("@info:credit", "The Maintainer ™️")
}
FormCard.FormDelegateSeparator {
above: lastaccount
below: addaccount
}
FormCard.FormButtonDelegate {
id: addaccount
icon.name: "list-add"
text: i18nc("@action:button", "Add a new account")
onClicked: console.info("Clicked!")
}
}
}
Как правило, разделители можно использовать везде, где между компонентами имеются существенные различия, хотя место их размещения выбирается самостоятельно. Например, в разделе «Общие» флажок отличается от предыдущих компонентов тем, что не начинается с текста; в разделе «Автосохранение» разделитель объединяет радиокнопки в группу; а в разделе «Учётные записи» добавление разделителя между последней учётной записью и кнопкой придаёт кнопке дополнительный акцент.
Свойства above и below довольно очевидны в применении: передаётся id компонентов выше и ниже разделителя. Если они заданы, разделитель будет немедленно скрываться, как только элемент выше или ниже выделен или на него наведён указатель. Они особенно полезны, например, когда компоненты создаются динамически и нельзя заранее определить, какой элемент окажется непосредственно перед разделителем или после него. Так было бы в разделе «Учётные записи» нашего приложения, если бы логика добавления новых учётных записей была реализована, и тогда можно было бы взять последний элемент модели.

Обратите внимание, что разделитель над параметром значка в системном лотке не показывается при наведении на него указателя.