Skip to main content
Перейти к содержимому

Делегаты форм на страницах параметров

Создание изящных пользовательских страниц параметров.

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 не нужен, а делегаты добавляются непосредственно в неё.

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
    }
}

Видимость каждой радиокнопки привязывается к переключателю, поэтому они показываются только тогда, когда переключатель включён.

Чтобы проверить флажок, можно добавить новый 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 компонентов выше и ниже разделителя. Если они заданы, разделитель будет немедленно скрываться, как только элемент выше или ниже выделен или на него наведён указатель. Они особенно полезны, например, когда компоненты создаются динамически и нельзя заранее определить, какой элемент окажется непосредственно перед разделителем или после него. Так было бы в разделе «Учётные записи» нашего приложения, если бы логика добавления новых учётных записей была реализована, и тогда можно было бы взять последний элемент модели.

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