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()
}
]
}
Först redigerar vi åtgärden från föregående handledning: bara en Kirigami.Action som aktiverar dialogens funktion open().
Nedräkning: lägga till dialogrutor
Den nya komponenten vi lägger till är Kirigami.Dialog. Dialogrutor dyker upp mitt på fönstret och kan användas för att tillhandahålla extra information relevant för det aktuella sammanhanget. De kan inte flyttas, men de anpassar sin egen storlek till fönstret.
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.
Header innehåller normalt en title och en stängningsknapp som kan inaktiveras med [showCloseButton] (docs:kirigami2;Dialog::showCloseButton). Footer innehåller normalt en stängningsknapp, och den kan ignoreras med standardButtons.
Vi ställde först in den för att visa knapparna "Ok" och "Avbryt", lade till lite utfyllnad och en rimlig preferredWidth. Den föredragna bredden är den förväntade standardstorleken på dialogrutan, som kan öka vid behov. Vi kan använda standard Kirigami.Units som vi tittar vidare på igen senare.
Sedan kommer vi till en Kirigami.FormLayout. I motsats till en ColumnLayout, är layouten av ingående komponenter automatisk och centrerad, med valfria beteckningar. Som namnet antyder, används den för att skapa inmatningsformulär.
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
.
Inom vart och ett av elementen i Controls.Textfield anger vi in egenskapen Kirigami.FormData.label som låter oss definiera beteckningar för dem. Formuläret visar rätt beteckning till vänster om vart och ett av textinmatningsfälten.
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:
|
|