Додавання діалогового вікна
Робимо нашу програму корисною
У нас є вікно, у нас є картки і у нас є дії. Але нам усе ще потрібне спосіб введення назви, опису та вибраної дати.
Одним зі способів досягти потрібного результату є створення сторінки, на якій ми розташуємо потрібні нам елементи для введення даних. Втім, надавати цілу сторінку для введення назви, опис та дати забагато.
Замість цього ми скористаємося діалоговим вікном.
Відкриття діалогового вікна
pageStack.initialPage: Kirigami.ScrollablePage {
// ...
actions: [
Kirigami.Action {
id: addAction
icon.name: "list-add"
text: i18nc("@action:button", "Add kountdown")
onTriggered: addDialog.open()
}
]
}
Спочатку внесемо зміни до дії з попереднього розділу підручника — просто додамо Kirigami.Action, яка вмикає функцію open() діалогового вікна.
Зворотний відлік — додавання діалогових вікон
Новим компонентом, який ми додаємо є Kirigami.Dialog. Діалогові вікна з'являються у центрі вікна. Ними можна скористатися для надання додаткових відомостей, які пов'язано із поточним вмістом вікна. Їх не можна пересувати, але їхній розмір адаптується до розміру головного вікна.
Kirigami.ApplicationWindow {
// ...
Kirigami.Dialog {
id: addDialog
title: i18nc("@title:window", "Add kountdown")
standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
padding: Kirigami.Units.largeSpacing
preferredWidth: Kirigami.Units.gridUnit * 20
// Компонування форми допомагають вирівняти і структурувати компонування із декількома
// елементами введення
Kirigami.FormLayout {
// Об'єкти Textfield надають вам змогу вводити текст у вузькому полі для введення тексту
Controls.TextField {
id: nameField
// Надає доступ до мітки, яку пов'язано із текстовим полем
Kirigami.FormData.label: i18nc("@label:textbox", "Name*:")
// Що робити після прийняття вхідних даних (тобто натискання клавіші Enter)? У цьому
// випадку фокусування буде пересунуто на наступне поле
onAccepted: descriptionField.forceActiveFocus()
}
Controls.TextField {
id: descriptionField
Kirigami.FormData.label: i18nc("@label:textbox", "Description:")
placeholderText: i18n("Optional")
// Знову ж таки, пересуває фокусування до наступного поля
onAccepted: dateField.forceActiveFocus()
}
Controls.TextField {
id: dateField
Kirigami.FormData.label: i18nc("@label:textbox", "ISO Date*:")
// D означає обов'язкове число у діапазоні 1-9, 9 — обов'язкове число у діапазоні
// 0-9
inputMask: "D999-99-99"
// Тут ми підтверджуємо дію, подібно до натискання кнопки «Гаразд»
onAccepted: addDialog.onAccepted()
}
Controls.Label {
text: "* = required fields"
}
}
// Тут маємо логіку діалогового вікна
}
// ...
}
У діалогових вікон, типово, є заголовок і підвал, обидва успадковані від Controls.Dialog.
До заголовка, типово, включають назву і кнопку закриття, яку можна вимкнути за допомогою showCloseButton. До підвалу, типово, включено кнопку закриття, і цю поведінку можна перевизначити за допомогою standardButtons.
Спочатку, ми налаштуємо його на показ кнопки «Гаразд» і «Скасувати», додамо фаски, та додамо прийнятну preferredWidth. Пріоритетною шириною є типовий очікуваний розмір діалогового вікна. Її може бути збільшено, якщо це потрібно. Ми можемо скористатися стандартним Kirigami.Units, до якого ми ще звернемося пізніше.
Далі, ми переходимо до Kirigami.FormLayout. На відміну від ColumnLayout, компонування його дочірніх компонентів є автоматичним і центрованим з необов'язковими мітками. Як можна зрозуміти з назви, його використовують для створення форм введення даних.
Ці компонування форм розроблено для роботи із різними типами полів введення, хоча тут ми використовуємо прості поля Controls.Textfield, якщо відповідають простим текстовим блоками для вписування простих текстових фрагментів.
Нами створено елементи Textfield, які працюють як:
- Поле для введення назви нашого відліку
- Поле для введення опису нашого відліку
- Поле для введення дати, до якої ми ведемо відлік і яка надається у форматі
YYYY-MM-DD
У кожному з цих елементів Controls.Textfield ми встановлюємо властивість Kirigami.FormData.label, що надає нам змогу визначити для них мітки. Форма покаже належні мітки ліворуч від кожного з цих полів для введення тексту.
Нарешті, ми також встановлюємо властивість onAccepted для вмикання методу forceActiveFocus() наступного поля; це призведе до перемикання активного поля, щойно користувач натисне клавішу ENTER, удосконалюючи зручність форми.
Ми також встановлюємо для текстового поля для нашої дати властивість із назвою inputMask. Встановлення значення D999-99-99
забороняє користувачеві вводити будь-що, що може зашкодити нормальній роботі програми (наприклад, звичайний текст). Користувач зможе вводити лише цифри, які згодом може бути перетворено на об'єкт дати.
Щойно роботу над інтерфейсом користувача діалогового вікна завершено, нам потрібно змінити поведінку вікна. Для цього нам потрібно три речі:
- Показ кнопки «Гаразд», лише якщо заповнено обов'язкові поля
- Додавання вхідних даних до моделі
- Очищення форми введення даних
Kirigami.Dialog {
// …Щойно Kirigami.Dialog буде ініціалізовано, нам потрібно буде створити нетипову прив'язку
// такого різновиду, що кнопка «Гаразд» стала видимою, лише якщо буде заповнено обов'язкові
// текстові поля. Для цього ми скористаємося Kirigami.Dialog.standardButton(button):
Component.onCompleted: {
const button = standardButton(Kirigami.Dialog.Ok);
// () => є функцією стрілочки JavaScript
button.enabled = Qt.binding( () => requiredFieldsFilled() );
}
onAccepted: {
// Прив'язку створено, але нам усе ще потрібно зробити її непридатною до клацання, якщо не
// заповнено поля
if (!addDialog.requiredFieldsFilled()) return;
appendDataToModel();
clearFieldsAndClose();
}
}
Першим, що слід зробити, є створення зв'язку між властивістю enabled кнопки «Гаразд» і перевіркою того, чи заповнено поля, що у цьому випадку слід зробити за допомогою Qt.binding() у JavaScript. У результаті рядок:
button.enabled = Qt.binding( () => requiredFieldsFilled() );
є подібним до прив'язок QML, які ми досі мали, як у такому псевдокоді:
enabled: requiredFieldsFilled()
Обробником сигналів, який вмикатиме кнопку «Гаразд», є onAccepted. Він лишається порожнім і таким, що не виконуватиме ніяких дій, якщо обов'язкові поля заповнено; у інших випадках він додаватиме поле введення до моделі і спорожнятиме діалогове вікно для наступного моменту, коли його буде відкрито.
Kirigami.Dialog {
// …Ми перевіряємо, чи є непорожнім nameField, і що dateField (для якого визначено inputMask) є
// повністю заповненим
function requiredFieldsFilled() {
return (nameField.text !== "" && dateField.acceptableInput);
}
function appendDataToModel() {
kountdownModel.append({
name: nameField.text,
description: descriptionField.text,
date: new Date(dateField.text)
});
}
function clearFieldsAndClose() {
nameField.text = ""
descriptionField.text = ""
dateField.text = ""
addDialog.close();
}
}
Для нашого обов'язкового поля name нам достатньо перевірити, чи є текстом поля порожній рядок. Для поля date, оскільки для нього визначено маску введення, замість цього, нам слід скористатися acceptableInput, значенням якого стане true, щойно усе поле буде заповнено, і у ньому міститимуться лише прийнятні символи.
Далі, метод append() нашої моделі списку kountdownModel
додає об'єкт JavaScript, включно із наданими нами властивостями.
Нарешті, ми спорожняємо текстові поля встановленням для їхніх властивостей text значення порожнього рядка, а потім виконуємо close().
Після зберігання наших файлів і збирання нашої програми ми зможемо додати наші власні зворотні відліки! Ми можемо додати останній штрих для удосконалення інтерфейсу, а саме вилучити фіктивний зворотний відлік, який ми мали у попередніх уроках:
|
|
По-друге, тепер, коли у нас є справжня дата, ми можемо обчислити час до цієї дати:
|
|
І по-третє, збільшуємо розмір вікна, щоб у нас було місце для наших нових карток:
|
|
Набагато краще.
Наша програма на поточний момент
Main.qml:
|
|