إضافة حوار
جعل تطبيقنا مفيدًا
لدينا نافذة، ولدينا بطاقات، ولدينا إجراءات. ومع ذلك، لا يزال يتعين علينا إيجاد طريقة لإدخال اسم ووصف وتاريخ من اختيارنا.
إحدى الطرق لفعل ذلك هي إنشاء صفحة جديدة نضع فيها عناصر الإدخال المطلوبة. لكن، تخصيص صفحة كاملة لتوفير اسم ووصف وتاريخ يبدو مبالغًا فيه بعض الشيء.
بدلاً من ذلك، سنستخدم حوارًا.

فتح الحوار
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 {
// تسمح لك حقول النص بإدخال نص في مربع نص رفيع
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.
نضبطه أولاً لعرض زر "موافق" وزر "إلغاء"، ونضيف بعض الحشو، ونضيف عرضًا مفضلاً معقولاً. العرض المفضل هو الحجم المبدئي المتوقع للحوار، والذي يمكن زيادته إذا لزم الأمر. يمكننا استخدام وحدات كيريجامي القياسية التي سنعود إليها لاحقًا.
ثم نصل إلى Kirigami.FormLayout. على عكس ColumnLayout، فإن تخطيط مكوناته الفرعية تلقائي ومتمركز، مع تسميات اختيارية. كما يوحي الاسم، يُستخدم لإنشاء نماذج إدخال.
صُممت تخطيطات النماذج هذه للعمل مع مجموعة متنوعة من أنواع الإدخال المختلفة، على الرغم من أننا نلتزم بمدخلات Controls.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);
// () => هي دالة سهمية في جافا سكريبت
button.enabled = Qt.binding( () => requiredFieldsFilled() );
}
onAccepted: {
// تم إنشاء الربط، لكننا ما زلنا بحاجة إلى جعله غير قابل للنقر ما لم تكن الحقول ممتلئة
if (!addDialog.requiredFieldsFilled()) return;
appendDataToModel();
clearFieldsAndClose();
}
}أول شيء يجب فعله هو إنشاء ربط بين خاصية enabled لزر موافق والتحقق مما إذا كانت الحقول ممتلئة، والذي يجب في هذه الحالة القيام به باستخدام Qt.binding() في جافا سكريبت. في الواقع، السطر:
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();
}
}بالنسبة لحقل الاسم المطلوب، كل ما نحتاج إليه هو التحقق مما إذا كان نص الحقل سلسلة فارغة. بالنسبة لحقل التاريخ، لأنه يحتوي على قناع إدخال، نحتاج إلى استخدام acceptableInput بدلاً من ذلك، والذي يصبح صحيحًا فقط بمجرد ملء الحقل بالكامل واحتوائه على أحرف مقبولة فقط.
ثم، طريقة append() لنموذج القائمة kountdownModel تضيف كائن جافا سكريبت يتضمن الخصائص التي قدمناها.
أخيرًا، نتأكد من مسح حقول النص عن طريق ضبط خصائص text الخاصة بها إلى سلسلة فارغة، ثم close() إغلاقه.
بمجرد حفظ ملفاتنا وبناء برنامجنا، سنكون قادرين على إضافة عداداتنا التنازلية المخصصة! يمكننا إجراء لمسة أخيرة لتحسين الواجهة، وهي إزالة العد التنازلي الوهمي الذي كان لدينا في الدروس السابقة:
| |
ثانيًا، الآن بعد أن أصبح لدينا تاريخ فعلي للعمل به، يمكننا حساب الوقت حتى التاريخ المذكور:
| |
وثالثًا، زيادة حجم النافذة بحيث يكون لدينا مساحة أكبر لبطاقاتنا الجديدة:
| |
أجمل بكثير.
تطبيقنا حتى الآن
Main.qml:
| |
