Lägga till en dialogruta
Göra vårt program användbart
Vi har ett fönster, vi har kort, och vi har åtgärder. Vi behöver ändå komma på något sätt att mata in ett namn, en beskrivning och ett datum vi väljer.
Ett sätt vi skulle kunna göra det är genom att skapa en nya sida där vi placerar inmatningselement. Dock verkar en hel sida tillägnad för att tillhandahålla namn, beskrivning och datum lite överdrivet.
Istället använder vi en dialogruta.
Öppna dialogrutan
pageStack.initialPage: Kirigami.ScrollablePage {
// ...
actions: [
Kirigami.Action {
id: addAction
icon.name: "list-add"
text: i18nc("@action:button", "Add kountdown")
onTriggered: addDialog.open()
}
]
}
First we edit the action from the previous tutorial: just a Kirigami.Action that triggers the dialog's open() function.
Nedräkning: lägga till dialogrutor
The new component we add is a Kirigami.Dialog. Dialogs appear at the center of the window and can be used to provide extra information relevant to the current content. They can't be moved, but they adapt their own size to the window.
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
// Formulärlayouter hjälper till att justera och strukturera en layout med mer indata
Kirigami.FormLayout {
// Textfält låter dig mata in text i en smal textruta
Controls.TextField {
id: nameField
// Tillhandahåller en beteckning kopplad till textfältet
Kirigami.FormData.label: i18nc("@label:textbox", "Name*:")
// Vad du ska göra efter att inmatning har accepterats (dvs. tryckt på
// returtangenten), i det här fallet flyttas fokus till nästa fält
onAccepted: descriptionField.forceActiveFocus()
}
Controls.TextField {
id: descriptionField
Kirigami.FormData.label: i18nc("@label:textbox", "Description:")
placeholderText: i18n("Optional")
// Återigen flyttar det fokus till nästa fält
onAccepted: dateField.forceActiveFocus()
}
Controls.TextField {
id: dateField
Kirigami.FormData.label: i18nc("@label:textbox", "ISO Date*:")
// D betyder ett obligatoriskt värde mellan 1-9, 9 betyder ett obligatoriskt värde
// mellan 0-9
inputMask: "D999-99-99"
// Här bekräftar vi operationen precis som att klicka på knappen Ok
onAccepted: addDialog.onAccepted()
}
Controls.Label {
text: "* = required fields"
}
}
// Dialogrutans logik ska finnas här
}
// ...
}
Dialogrutor har normalt en header och en [footer](https://doc.qt .io/qt-6/qml-qtquick-controls-dialog.html#footer-prop), båda ärvda från Controls.Dialog.
The header by default includes a title and a close button that can be disabled with showCloseButton. The footer by default includes a close button, and it can be overridden with standardButtons.
We first set it to show an "Ok" button and a "Cancel" button, add some padding, and add a reasonable preferredWidth. The preferred width is the default expected size of the dialog, which can increase if needed. We can use standard Kirigami.Units that we will revisit later on.
Then we come to a Kirigami.FormLayout. Unlike a ColumnLayout, the layout of its child components is automatic and centered, with optional labels. As the name implies, it is used to create input forms.
Formulärlayouter är konstruerade för att arbeta med ett stort antal typer av inmatning, även om vi håller oss till enkla Controls.Textfield, som ger oss enkla textrutor att skriva in saker i.
Vi har skapat elementet Textfield som fungerar som:
- Indata för namnet på vår nedräkning
- Indata för beskrivningen av vår nedräkning
- Indata för datumet vi räknar ner till, som måste anges på formatet
ÅÅÅÅ-MM-DD
.
Within each of these Controls.Textfield elements, we are setting a Kirigami.FormData.label property that lets us define labels for them. The form will present the correct labels to the left of each of these text input fields.
Slutligen ställer vi också in egenskapen onAccepted för att använda metoden [forceActiveFocus()](https:/ /doc.qt.io/qt-6/qml-qtquick-item.html#forceActiveFocus-method) för följande fält. Det byter det aktiva fältet när användaren trycker på returtangenten, vilket förbättrar formulärets användbarhet.
Vi har också ställt in en egenskap som kallas inputMask i textfältet för vårt datum. Att ställa in den till `D999-99-99" förhindrar oss från att mata in någonting som kan förstöra programmets funktion (såsom text), och begränsar dem att bara mata in siffror som vi sedan kan försöka tolka som ett datumobjekt.
När användargränssnittet för dialogrutan är klart måste vi ändra hur det beter sig. För att göra det behöver vi tre saker:
- Visa bara knappen Ok när de obligatoriska fälten är ifyllda
- Lägga till den inmatade informationen i modellen
- Rensa inmatningsformuläret
Kirigami.Dialog {
// ... När Kirigami.Dialog väl har initierats vill vi skapa en egen bindning för att endast göra
// Ok-knappen synlig om de obligatoriska textfälten är ifyllda. För att göra det använder vi
// Kirigami.Dialog.standardButton(button):
Component.onCompleted: {
const button = standardButton(Kirigami.Dialog.Ok);
// () => är en pilfunktion i Javascript
button.enabled = Qt.binding( () => requiredFieldsFilled() );
}
onAccepted: {
// Bindningen är skapad, men vi måste fortfarande göra den oklickbar om fälten inte är
// ifyllda
if (!addDialog.requiredFieldsFilled()) return;
appendDataToModel();
clearFieldsAndClose();
}
}
Det första som behöver göras är att skapa en bindning mellan Ok-knappens egenskap enabled och en kontroll av om fälten är ifyllda, vilket i detta fall måste göras med [Qt.binding()](https://doc.qt.io/qt-6/qtqml-syntax-propertybinding.html#creating- egenskapsbindningar-från-javascript) i JavaScript. I själva verket är raden:
button.enabled = Qt.binding( () => requiredFieldsFilled() );
som liknar de QML-bindningar vi har sett hittills, liksom i följande pseudokod:
enabled: requiredFieldsFilled()
Signalhanteraren som aktiverar Ok-knappen är onAccepted. Den förblir tom och utan att göra någonting om de obligatoriska fälten är ifyllda. Annars lägger den till indata i modellen och rensar dialogrutan till nästa gång den öppnas.
Kirigami.Dialog {
// ... Vi kontrollerar att namnfältet inte är tomt och att datumfältet (som har en inputMask) är
// helt ifyllt
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();
}
}
För vårt obligatoriska namnfält är allt vi behöver göra att kontrollera om fälttexten är en tom sträng. För datumfältet, eftersom det har en inmatningsmask, behöver vi istället använda acceptableInput, vilket endast är sant när hela fältet är ifyllt och endast innehåller acceptabla tecken.
Sedan lägger metoden append() i vår listmodell kountdownModel
till ett Javascript-objekt som inkluderar egenskaperna vi har tillhandahållit.
Till sist, säkerställer vi att textfälten är tomma genom att ställa in deras egenskap text till en tom sträng, och sedan stänga den med close().
När vi har sparat våra filer och byggt vårt program kommer vi att kunna lägga till våra egna anpassade nedräkningar! Vi kan göra en sista touch för att förbättra gränssnittet, nämligen ta bort exempelnedräkningen vi hade i de tidigare lektionerna:
|
|
För det andra, nu när vi har ett verkligt datum att leka med, kan vi beräkna tiden fram till datumet:
|
|
Och för det tredje öka fönsterstorleken så att vi har mer plats för våra nya kort:
|
|
Mycket trevligare.
Vårt program så långt
Main.qml:
|
|