Компонування, панелі списків і картки
Компонування ваших даних
Тепер, коли ми вже розуміємо, як працюють сторінки, час додати можливості до них. Ми розглянемо декілька важливих компонентів та елементів компонування, які будуть корисними при створенні дизайну нашої програми.
Наприкінці цього розділу ви матимете програму, яка виглядатиме лаконічно.
ListView
Якщо ви колись користувалися Discover, NeoChat або Системними параметрами Плазми, ви вже бачили ListView. Доволі прості, ListView надають вам змогу показувати дані у форматі списку.
pageStack.initialPage: Kirigami.ScrollablePage {
// ...
Kirigami.CardsListView {
id: cardsView
model: kountdownModel
delegate: kountdownDelegate
}
}
Це може здатися якимось шифром, але не переймайтеся. Розпочнімо з початку.
Ми додаємо цей компонент до нашого Kirigami.ScrollablePage з останньої частини підручника.
Ми скористалися Kirigami.CardsListView. Це ListView, який надає нам змогу просто показувати картки у форматі списку. Втім, ListView створено для показу даних, які взято з моделі — для автоматичного заповнення списку набором даних, які ми вказали. Ось тут нам стане у пригоді властивість model
— у нашому прикладі, вона вказує на kountdownModel
.
Модель
Kirigami.ApplicationWindow {
// ...
ListModel {
id: kountdownModel
// Кожне з ListElement є елементом списку, що містить дані
ListElement {
name: "Dog birthday!!"
description: "Big doggo birthday blowout."
date: 100
}
}
// ...
}
Ми додаємо нашу kountdownModel
до Kirigami.ApplicationWindow з останньої частини підручника.
Модель визначає спосіб, у який структуровано запис даних. Зараз наша kountdownModel
складається лише з одного елемента. Структурування дані у нашій kountdownModel
можна бачити у нашому ListElement: вони містять назву, опис і дату. Це не жорстка структура, і у вашій моделі можуть бути інші типи даних. Перші два елементи є лише рядками, а третій є числом, яким ми користуємося як замінником.
Нотатка
Оскільки QML побудовано на основі JavaScript, багатьма можливостями цієї мови можна скористатися у файлах QML. Втім, до змінних QML слід додавати префікс «property», якщо код не перебуває у блоці JS. Докладніше про це можна дізнатися з відповідної сторінки.Крім того, моделі є корисними через те, як їх можна змінювати, використовуючи декілька методів. Серед важливих методів такі:
- ListModel.append(yourobject: jsobject) додає вказаний вами об'єкт JavaScript (JSObject) до ListModel і розташовує його після останнього запису у моделі. Щоб це відбувалося належним чином, вам слід надати JSObject із належними властивостями і відповідними типами даних.
- ListModel.get(index: int) повертає JSObject із наданим індексом розташування.
- ListModel.remove(index: int, count: int) вилучає JSObject із наданим індексом розташування і вказану кількість
count
об'єктів після нього (1 включає лише JSObject із наданим індексом) - ListModel.set(index: int, ваш_об'єкт: jsobject) замінює значення запису із наданим індексом розташування значеннями наданого вами об'єкта
yourobjectваш_об'єкт
. Ті самі правила, що і дляappend()
.
Делегати
Хоча наша kountdownModel
містить дані, які буде показано, наш kountdownDelegate
оброблятиме спосіб показу даних у ListView. Для цього ми використовуємо Kirigami.CardsListView, який було розроблено для показу делегатів типу карток, і ці делегати буде візуально відтворено за допомогою Kirigami.AbstractCard.
Делегати автоматично отримують властивості ListElements, які вказано у нашій моделі. Тому ми можемо просто посилатися на їхні властивості name
, description
і date
так, наче це була б звичайні змінні у нашому делегаті.
Побудова делегованої картки
Компонент, який представляє нашого делегата, можна додати всередині нашого Kirigami.ApplicationWindow. Далі, ми перевіримо, яке завдання виконує кожна частина нашого компонента-делегата.
Kirigami.ApplicationWindow {
// ...
Component {
id: kountdownDelegate
Kirigami.AbstractCard {
contentItem: Item {
// implicitWidth/Height визначають природну ширину і висоту пункту, якщо ширину або
// висоту не вказано явним чином. Наведений нижче код визначає бажані розміри
// компонента на основі його вмісту.
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
GridLayout {
id: delegateLayout
anchors {
left: parent.left
top: parent.top
right: parent.right
}
rowSpacing: Kirigami.Units.largeSpacing
columnSpacing: Kirigami.Units.largeSpacing
columns: root.wideScreen ? 4 : 2
Kirigami.Heading {
Layout.fillHeight: true
level: 1
text: date
}
ColumnLayout {
Kirigami.Heading {
Layout.fillWidth: true
level: 2
text: name
}
Kirigami.Separator {
Layout.fillWidth: true
visible: description.length > 0
}
Controls.Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: description
visible: description.length > 0
}
}
Controls.Button {
Layout.alignment: Qt.AlignRight
Layout.columnSpan: 2
text: i18n("Edit")
// onClicked: буде зроблено… невдовзі!
}
}
}
}
}
// ...
}
implicitWidth та implicitHeight
Перша частина, яку ми розглянемо, полягає у тому, як керувати шириною та висотою нашого компонента:
Kirigami.AbstractCard {
contentItem: Item {
implicitWidth: delegateLayout.implicitWidth
implicitHeight: delegateLayout.implicitHeight
GridLayout {
id: delegateLayout
// ...
}
}
}
Розглядаючи наш Kirigami.AbstractCard, першими встановленими нами властивостями є implicitWidth і implicitHeight. Ми надаємо їм значення delegateLayout.implicitWidth
і delegateLayout.implicitHeight
, тобто implicitWidth
і implicitHeight
елемента GridLayout
.
Неявними ширинами і висотами є властивості, які доступні у будь-якому Item, і які працюють як підказки. Вони є або типовими або резервними варіантами, якщо для цих компонентів не встановлено явно ширини або висоти. Типовими значеннями цих величин є 0x0, тому дуже важливо визначати ці значення у простих компонентах Item, як це зроблено вище.
Тут ми встановили значення implicitWidth
і implicitHeight
нашого Kirigami.AbstractCard у значення GridLayout нижче для того, щоб вони не вилізли за картку. Таким чином, картка займе стільки місця, скільки потрібно для її вмісту.
Компонування
GridLayout перебуває всередині компонента Item, який ми надали для властивості contentItem. Це Item, який містить те, що буде показано у вашій картці.
Нам також потрібно вибрати компонування для наших компонентів так, щоб вони не просто накопичувалися один над одним. Існує три основних типи, один з яких ми можемо вибрати:
- ColumnLayout розташовує ваші компоненти вертикально, у один стовпчик
- RowLayout розкладає ваші компоненти горизонтально у один рядок
- GridLayout розкладає ваші компоненти у таблицю із вибраним вами компонуванням
З ColumnLayout і RowLayout усе, що нам слід зробити, — це записати наші компоненти всередину компонента Layout. Як ви можете бачити, ми використали GridLayout, що потребує додаткового опису вручну.
GridLayout {
id: delegateLayout
anchors {
left: parent.left
top: parent.top
right: parent.right
}
rowSpacing: Kirigami.Units.largeSpacing
columnSpacing: Kirigami.Units.largeSpacing
columns: root.wideScreen ? 4 : 2
// ...
}
Першим, що ви бачите, є наш anchor
. Система прив'язок QtQuick надає зручний спосіб визначення розташування ваших компонентів у певних місцях батьківського компонента. Ми прив'язали наш GridLayout ліворуч, згори і праворуч до батьківської картки, забезпечивши розтягування вмісту на усю картку.
Далі, ми вказали інтервал між рядками і стовпчиками у нашій таблиці, щоб наші компоненти не накладалися один на одного. У Kirigami передбачено декілька зручних попередньо визначених одиниць для використання з цією метою:
Одиниця Kirigami | Пікселі |
---|---|
smallSpacing | 4px |
largeSpacing | 8px |
gridUnit | 18px |
Нотатка
Група з візуального дизайну KDE (VDG) надає багато настанов щодо зручності інтерфейсу щодо різних модулів, які визначено у Плазмі і Kirigami.Як ви можливо пам'ятаєте, root
є ідентифікатором нашого Kirigami.ApplicationWindow. Він надає властивість wideScreen, яку використовують для визначення того, чи є поточний екран пристрою широкоформатним (тобто монітором комп'ютера або екраном телефону в альбомному режимі). Тут ми використовуємо тернарну умову для зміни кількості стовпчиків у нашій таблиці залежно від використаного екрана: якщо він є широкоформатним, у таблиці буде 4 стовпчики, інакше їх буде 2.
Внутрішні компоненти
Ми могли б просто створити три мітки у нашому компоненті-делегаті, і все. Але це не виглядало б аж надто привабливо. Ми ж скористаємося декількома додатковими зручними компонентами:
GridLayout {
// ...
Kirigami.Heading {
Layout.fillHeight: true
level: 1
text: date
}
ColumnLayout {
Kirigami.Heading {
Layout.fillWidth: true
level: 2
text: name
}
Kirigami.Separator {
Layout.fillWidth: true
visible: description.length > 0
}
Controls.Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: description
visible: description.length > 0
}
}
Controls.Button {
Layout.alignment: Qt.AlignRight
Layout.columnSpan: 2
text: i18n("Edit")
}
}
- Ліворуч, Kirigami.Heading: використовує
date
зListElement
як заголовок першого рівня. - Посередині, ColumnLayout: містить Kirigami.Heading, де показано назву завдання; Kirigami.Separator, який додає горизонтальну лінію; і Controls.Label, який показу необов'язковий опис завдання. Останні два компоненти мають властивість visible, значення якої визначається перевіркою того, чи є порожнім опис, — компоненти буде показано, залежно від результату перевірки
description.length > 0
. - Праворуч, Controls.Button: кнопка, яка щось робитиме… невдовзі!
Наша програма на поточний момент
Main.qml:
|
|
Отже, маємо нашу базову картку!
Виконанням цих кроків ми заклали підвалини для додавання функціональних можливостей до нашої програми.