Delegados de Form en sus páginas de preferencias
Los complementos de Kirigami son un conjunto adicional de componentes visuales que funcionan bien en el móvil y en el escritorio, con la garantía de ser multiplataforma. Usan Kirigami internamente para crear sus componentes.
Ha aprendido a añadir las páginas «Acerca de» y «Acerca de KDE» a su aplicación. Ahora podrá usar los mismos componentes internos para crear sus páginas de preferencias.
La estructura del proyecto debería parecerse a esto:
addonsexample
├── CMakeLists.txt
├── main.cpp
├── Main.qml
├── MyAboutPage.qml
└── SettingsPage.qml
Cambios necesarios
Cambie Main.qml
para que incluya nuestra nueva página de preferencias:
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)
}
}
}
}
}
Ahora podemos comenzar a revisar los componentes usados para crear nuestra página de «Preferencias»: la tarjeta de formulario y sus delegados.
Delegados de Form
FormCard y FormCardPage
FormCard.FormCard es el componente principal que usaremos para agrupar todos sus componentes hijos, los «delegados».
Ya hemos usado una tarjeta de formulario en la introducción a los complementos de Kirigami. Su propósito principal es el de servir como contenedor para otros componentes con un color distinto al del fondo, de un modo similar a una Kirigami.Card.
Cree un nuevo archivo SettingsPage.qml
:
import QtQuick
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormCard {
// Aquí es donde van nuestros delegados.
}
FormCard.FormCard {
// Aquí es donde van nuestros delegados.
}
}
Como estamos creando un archivo QML distinto para nuestra página de «Preferencias», y como posiblemente necesitaremos prepararla para que permita usar desplazamiento en la página, usamos una FormCard.FormCardPage
, que hereda de Kirigami.ScrollablePage.
Lo bueno de la página de la tarjeta de formulario es que viene con un diseño interno, por lo que no necesita ningún «ColumnLayout» adicional, y nuestros delegados se pueden añadir directamente al mismo.
Nota
Se pueden usar delegados de FormCard directamente con una Kirigami.ScrollablePage, aunque en este caso tendrá que añadir sus propios diseños.FormHeader
Para cada FormCard que quiera crear, puede crear una FormHeader antes. La cabecera usa texto en negrita y se muestra justo encima de la tarjeta de formulario.
import org.kde.kirigamiaddons.formcard as FormCard
FormCard.FormCardPage {
FormCard.FormHeader {
title: i18n("General")
}
FormCard.FormCard {
// Nuestros delegados van aquí...
}
FormCard.FormHeader {
title: i18n("Accounts")
}
FormCard.FormCard {
// Nuestros delegados van aquí...
}
}
FormTextDelegate y FormSectionText
Empecemos de forma sencilla, con texto sin formato.
FormSectionText
añade un fino delegado que contiene una etiqueta. FormTextDelegate
tiene texto y una descripción desactivada.
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 ™️")
}
}
}
Añadimos un texto de relleno para una hipotética detección de tema. Si queremos que se detecte realmente el esquema de color, se puede hacer posteriormente de forma similar a como se hace en Neochat (aquí tiene el código), que usa un modelo de C++ con KColorSchemeManager.
En la sección de «Cuentas en línea», vemos una propiedad adicional: leading
. Podemos añadir un Item a ella para que aparezca antes del texto. La propiedad opuesta, trailing
, permite mostrar un Item tras el texto, aunque no la usaremos en nuestro programa.
Aquí usamos un Kirigami.Icon por simplicidad, aunque también se puede usar un Kirigami.Avatar que obtiene la información de un modelo, como se hace en Neochat aquí.
Debería terminar pareciéndose a esto:
FormButtonDelegate
El FormButtonDelegate es visualmente similar a un FormTextDelegate, aunque se puede hacer clic sobre él y muestra una flecha que apunta hacia la derecha. Ya lo hemos usado en la introducción a los complementos de Kirigami.
Mientras que FormTextDelegate tiene las propiedades leading
y trailing
para mostrar un elemento antes y después del contenido principal, FormButtonDelegate solo tiene la propiedad leading
, ya que la parte derecha está ocupada por la flecha.
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!")
}
}
}
Hemos usado la propiedad icon.name
para hacer que aparezca un icono con el signo más (+) después del espacio donde aparecería leading
y delante del contenido principal. Esto es un patrón común para indicar que el botón añadirá algo a una lista.
Dado que este ejemplo tiene fines ilustrativos sencillos, no profundizamos en lo que se haría tras pulsar el botón: solo muestra «¡Pulsado!» en la terminal. Podríamos crear una nueva página para crear una cuenta que añada otro usuario a un modelo y luego mostrar la página en la vista, de forma similar a lo que hicimos en Main.qml
.
FormRadioDelegate, FormCheckDelegate y FormSwitchDelegate
Los botones de opción, las casillas de verificación y los interruptores son componentes que se usan con mucha frecuencia en cualquier interfaz de usuario. Los complementos de Kirigami los proporcionan como FormRadioDelegate, FormCheckDelegate y FormSwitchDelegate.
Sus únicas propiedades principales son text
y description
. Se usan de forma diferente porque heredan de AbstractButton, por lo que se espera que use sus señales y manejadores: «checked» y «onChecked», «toggled» y «onToggled», «clicked» y «onClicked».
Queremos dotar de cierta funcionalidad para guardar automáticamente a nuestra aplicación, y solo queremos mostrar sus preferencias si el usuario ha activado dicha funcionalidad. Creamos una nueva sección usando una FormCard y una FormHeader, a la que añadiremos un FormSwitchDelegate y un 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
}
}
Vinculamos la visibilidad de cada botón de opción a un interruptor, por lo que solo aparecen cuando el interruptor está activado.
Mejores prácticas
Pulse aquí para leer más
Si tiene experiencia en programación con lenguajes imperativos, como C++, es posible que tenga la tentación de definir la propiedad checked
del interruptor para cambiar la visibilidad de los botones de opción a true
con una asignación de JavaScript, como:
checked: {
radio1.visible = true;
radio2.visible = true;
radio3.visible = true;
}
Esto no es muy eficiente para el lenguaje declarativo de QML y sus señales y ranuras. Trate de usar enlaces QML, como en el caso de visible: autosave.checked
, tanto como sea posible en lugar de expresiones JavaScript.
Consulte esta paǵina para más detalles.
Para probar nuestra casilla de verificación, podemos añadir un nuevo FormCheckDelegate a nuestra sección «General».
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!")
}
}
}
}
Aquí usamos el manejador de señal onToggled
para mostrar un texto de relleno para simular un icono de la bandeja del sistema que aparece en el sistema. Si realmente lo necesita, podría implementar fácilmente un icono de la bandeja del sistema usando SystemTrayIcon.
Hasta ahora, nuestra aplicación debería parecerse a esto:
FormComboBoxDelegate
El componente común ComboBox se puede crear usando un FormComboBoxDelegate.
Esta lista desplegable tiene varias propiedades útiles que podemos usar: editable
, displayText
y displayMode
.
Defina editable: true
para permitir que el usuario pueda modificar el texto de la lista desplegable, que será de utilidad si necesita añadir nuevas opciones de la lista desplegable.
Siempre que necesite mostrar texto adicional antes de cada opción, puede usar algo semejante a displayText: "Perfil: " + textoActual
:
Y la más interesante, que usaremos en nuestro ejemplo, es displayMode
. Puede tener tres opciones:
- FormComboBoxDelegate.ComboBox: el pequeño cuadro estándar que muestra una lista de opciones.
- FormComboBoxDelegate.Dialog: un diálogo que muestra una lista de opciones en el centro de la ventana, como una Kirigami.OverlaySheet.
- FormComboBoxDelegate.Page: una nueva página que contiene una lista de opciones que se muestran en una ventana separada.
Añada lo siguiente entre los delegados "Esquema de color actual" y "Mostrar bandeja del sistema" de la tarjeta "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"]
}
Con la casilla de verificación, nuestra página de «Preferencias» debería parecerse a esto:
FormDelegateSeparator
Nuestra página de «Preferencias» va tomando forma, aunque cada sección está empezando a ser demasiado larga. Podemos añadir unos cuantos FormDelegateSeparators para que la página quede más clara:
import QtQuick 2.15
import org.kde.kirigami 2.20 as Kirigami
import org.kde.kirigamiaddons.formcard 1.0 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!")
}
}
}
Generalmente, puede usar separadores siempre que observe distinciones importantes entre los componentes, aunque la decisión de dónde colocarlos es, en última instancia, suya. Por ejemplo, en la sección «General», la casilla de verificación se diferencia de componentes anteriores en que no comienza con texto; en la sección «Guardar automáticamente», el separador agrupa los botones de opciones; y en la sección «Cuentas», si añade un separador entre la última cuenta y el botón, proporcionará un enfoque adicional para el botón.
Las propiedades above
y below
son casi autoexplicativas cuando se trata de su uso: se pasa el id
de los componentes que hay por encima y por debajo del separador. Cuando se configuran, el separador desaparecerá rápidamente cada vez que se resalte o se coloque el cursor sobre el elemento de encima o de debajo. Son más útiles, por ejemplo, cuando necesita generar componentes dinámicamente y no puede asumir automáticamente el elemento que aparecerá inmediatamente antes o después del separador. Ese sería el caso en la sección «Cuentas» de nuestra aplicación una vez que se implementara la lógica para añadir nuevas cuentas, en cuyo caso siempre podríamos tomar el último elemento del modelo para hacerlo.
Observe cómo el separador sobre la preferencia del icono de la bandeja del sistema no aparece mientras está sobre él.