Компонування, панелі списків і картки
Компонування ваших даних
Тепер, коли ми вже розуміємо, як працюють сторінки, час додати можливості до наших. Ми розглянемо декілька важливих компонентів та елементів компонування, які будуть корисними при створенні дизайну нашої програми.
Не лякайтеся великих фрагментів коду! Ми розберемо усе, що ми ще не обговорювали раніше, і наприкінці цього розділу ви матимете програму, яка виглядатиме лаконічно.
ListView
Якщо ви колись користувалися Discover, NeoChat або Системними параметрами Плазми, ви вже бачили ListView. Доволі прості, ListView надають вам змогу показувати дані у форматі списку.
Kirigami.CardsListView {
id: layout
model: kountdownModel
delegate: kountdownDelegate
}
Це може здатися якимось шифром, але не переймайтеся. Розпочнімо з верхньої частини.
Першим, що чи зауважите, є те, що ми скористалися Kirigami.CardsListView
. Це ListView, який надає нам змогу просто показувати картки у форматі списку. Втім, ListView створено для показу даних, які взято з моделі — для автоматичного заповнення списку набором даних, які ми вказали. Ось тут нам стане у пригоді властивість model
— у нашому прикладі, вона вказує на kountdownModel
.
Модель
ListModel {
id: kountdownModel
// Кожне з ListElement є елементом списку, що містить дані
ListElement { name: "Dog birthday!!"; description: "Big doggo birthday blowout."; date: 100 }
}
Модель визначає спосіб, у який структуровано запис даних. Структурування елементів kountdownModel можна бачити у нашому ListElement: вони містять назву, опис і дату. Перші два елементи є лише рядками, а третій є числом, яким ми користуємося як замінником.
Нотатка
Since QML is built on top of JavaScript, many of this language's features are available for use in QML files. However, JavaScript variables have to be prefixed withproperty
in QML.Крім того, моделі є корисними через те, як їх можна змінювати, використовуючи декілька методів. Серед важливих методів такі:
- ListModelName.append(jsobject ваш_об'єкт) додає вказаний вами об'єкт JavaScript до ListModel і розташовує його після останнього запису у моделі. Щоб це відбувалося належним чином, вам слід надати об'єкт JavaScript із належними властивостями і відповідними типами даних.
- ListModelName.get(int індекс) повертає JSObject із наданим індексом розташування.
- ListModelName.remove(int індекс, int кількість) вилучає JSObject із наданим індексом розташування і вказану кількість об'єктів після нього (1 включає лише JSObject із наданим індексом)
- ListModelName.set(int індекс, jsobject ваш_об'єкт) замінює значення запису із наданим індексом розташування значеннями наданого вами об'єкта ваш_об'єкт. Ті самі правила, що і для
.append
.
Делегат
Делегат керує тим, як ваші дані ListModel буде показано у ListView. Елементи CardsListView створено зручними для використання із делегатами типу карток, і справді, ми скористалися елементом Kirigami.AbstractCard
як нашим делегатом у наведеному вище фрагменті коду.
Делегати автоматично отримують властивості ListElement, які вказано у нашій моделі. Тому ми можемо просто посилатися на властивості name
, description
і date
наших ListElement так, наче це була б звичайна змінна у нашому делегаті.
Побудова нашої делегованої картки
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 < 100000) ? date : i18n("%1 days", Math.round((date-Date.now())/86400000))
}
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
. Неявними ширинами і висотами є властивості, які встановлено подібно до типових, тобто якщо немає явно заданих ширини і висоти для цих компонентів. Тому ми встановили для implicitWidth
і implicitHeight
нашого Kirigami.AbstractCard
у значення GridLayout
нижче, щоб GridLayout
не розповзся за картку.
Компонування
GridLayout
перебуває всередині компонента Item
, який надано для властивості contentItem
. Це запис, який містить те, що буде показано у вашій картці.
Нам також потрібно вибрати компонування для наших компонентів так, щоб вони не просто накопичувалися один над одним. Існує три основних типи, один з яких ми можемо вибрати:
ColumnLayout
розташовує ваші компоненти вертикально, у один стовпчикRowLayout
розкладає ваші компоненти горизонтально у один рядокGridLayout
розкладає ваші компоненти у таблицю із вибраним вами компонуванням
З ColumnLayout і RowLayout усе, що нам слід зробити, — це записати наші компоненти всередину компонента Layout. Як ви можете бачити, ми використали табличне компонування, що потребує додаткового опису вручну.
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's Visual Design Group (VDG) has a lot more information about different units defined within Plasma and Kirigami on the Human Interface Guidelines site.Тут ми також скористалися умовою для варіювання кількості стовпчиків у нашій таблиці залежно від параметрів використаного екрана. Якщо використано широкий екран (тобто монітор комп'ютера або телефон у альбомному режимі) у таблиці буде 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
: кнопка, яка щось робитиме… невдовзі!
Наша програма на поточний момент
Отже, маємо нашу базову картку!
Виконанням цих кроків ми заклали підвалини для додавання функціональних можливостей до нашої програми.