Skip to main content
تخط المحتوى

مناظر القوائم

يمكن لمنظر القائمة مساعدتك في عرض العديد من المكونات ديناميكيًا بسهولة.

يمكن أن تساعدك عروض القوائم في عرض الكائنات من نموذج بطريقة جذابة. لاستخدام عرض قائمة، عليك تتبع ثلاثة أشياء:

  1. النموذج، الذي يحتوي على البيانات التي تريد أن يعرضها عرض القائمة الخاص بك
  2. المفوض، الذي يحدد كيف سيُعرض كل عنصر في النموذج
  3. عرض القائمة نفسه، الذي سيعرض المعلومات من النموذج وفقًا للمفوض

إذا كنت ترغب في مزيد من التوضيح، فإن توثيق كيوتي لديه صفحة إعلامية حول الموضوع.

أساسيات النماذج والعروض

عرض القائمة له خاصيتان أساسيتان يجب أن ننتبه إليهما:

  • model، التي تقبل البيانات أو id الكائن الذي يحمل البيانات
  • delegate، التي تقبل المكون الذي سنستخدمه لعرض البيانات في النموذج

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

هذا مثال يحتوي على عرض قائمة واحد، ونموذج واحد، ومفوض واحد، باستخدام Kirigami.SubtitleDelegate:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

ونفس المثال تمامًا، مضمنًا:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products (inline)"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: ListModel {
                id: plasmaProductsModel
                ListElement { product: "Plasma Desktop"; target: "desktop" }
                ListElement { product: "Plasma Mobile";  target: "mobile" }
                ListElement { product: "Plasma Bigscreen"; target: "TVs" }
            }
            delegate: Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

فهم النماذج

يحتوي النموذج على البيانات التي ستُستخدم لملء عرض القائمة. الطرق المختلفة لاستخدام النماذج لها طرق مختلفة للوصول إلى البيانات:

طريقة الاستخدامكيفية الوصولمتى يُستخدم
نماذج كيوتي بأكثر من دورmodel.index, model.someroleفي معظم الحالات
نماذج كيوتي بدور واحدmodel.index, model.somerole, model.modelDataفي معظم الحالات، للنمذجة الأولية
نموذج مصفوفة جافاسكريبتmodel.index, model.modelDataللنمذجة الأولية
نموذج عدد صحيحmodel.index, model.modelDataللنمذجة الأولية

يمكنك القراءة عن طرق أخرى لاستخدام النماذج في وثائق كيوتي.

في الجدول أعلاه، تشير "نماذج كيوتي" إلى كل من النماذج الخاصة بـ C++ مثل QAbstractListModel والنماذج الخاصة بـ QML مثل ListModel. ستركز صفحة البرنامج التعليمي هذه فقط على النماذج الخاصة بـ QML. في ما بعد نقدم برنامجًا تعليميًا لـ ربط نماذج C++ بـ QML باستخدام QAbstractListModel.

الخاصية model.index متاحة لكل نموذج وتحتوي على الفهرس (الموضع) لكل مفوض. يمكن اختصارها إلى index للتسهيل.

الخاصية model.somerole المذكورة أعلاه هي مجرد عنصر نائب، وليست خاصية محددة تأتي من QML: somerole يمكن أن يكون أي دور يُعرّفه النموذج. في مثال الكود الأول في هذه الصفحة المعروض أعلاه الجدول، نموذج plasmaProductsModel له دور product وtarget، والتي يمكن الوصول إليها بـ model.product وmodel.target على التوالي.

كما يمكن اختصار model.index إلى index، يمكن اختصار كل خاصية model.somerole إلى somerole فقط (مثل product) للتسهيل، لكن يُوصى بتحويلها إلى خصائص مطلوبة:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products (shortened with required properties)"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string product
                required property string target
                required property int index
                text: `${product} is KDE software developed for ${target} stored at index ${index} of this list`
            }
        }
    }
}

بالإضافة إلى ذلك، إذا كان النموذج يحتوي على دور واحد فقط أو لا يحتوي على أي دور، يمكن الوصول إلى بياناته أيضًا بالخاصية model.modelData، والتي يمكن اختصارها إلى modelData (وبالتالي ستحتاج أيضًا إلى أن تكون خاصية مطلوبة):

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami


Kirigami.ApplicationWindow {
    title: "List of KDE software"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: kdeSoftwareModel
            delegate: listDelegate
        }
        ListModel {
            id: kdeSoftwareModel
            ListElement { software: "Dolphin" }
            ListElement { software: "Discover" }
            ListElement { software: "KHelpCenter" }
            ListElement { software: "KCalc" }
            ListElement { software: "Ark" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: modelData // هذا يطابق model.software
            }
        }
    }
}

للمقارنة، إليك كيف سيبدو الكود أعلاه مع مصفوفة جافاسكريبت، بدون دور:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of KDE software (as JS array)"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: ["Dolphin", "Discover", "KHelpCenter", "KCalc", "Ark"]
            delegate: listDelegate
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: modelData
            }
        }
    }
}

استخدام عدد صحيح للنموذج يمكن أن يكون مفيدًا لحالات محددة جدًا، وهي النمذجة الأولية والاختبارات:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "Simple list of indexes"
    width: 400
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            anchors.fill: parent
            model: 30
            delegate: listDelegate
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                required property string modelData
                text: `This delegate's index is: ${modelData}`
            }
        }
    }
}

فهم العروض والمفوضين

لنعد إلى المثال الأصلي:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            // anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target} stored at index ${model.index} of this list`
            }
        }
    }
}

على عكس النموذج (الذي يحتوي فقط على البيانات) والمفوض Component (الذي يظهر فقط عند إنشاء مثيل له)، فإن العرض هو مكون مرئي يُنشأ مثيله فورًا ولذا يحتاج إما إلى تعيين أبعاده أو استخدام المراسي أو التخطيطات.

نظرًا لأن العروض عادةً ما تكون قوائم محتوى يرغب المستخدم في التمرير خلالها، فعند إضافتها إلى Kirigami.ScrollablePage، تصبح العروض المحتوى الرئيسي مع حشوة صغيرة حولها، ولا حاجة لجعلها تملأ الصفحة. عند إضافة العرض إلى Kirigami.Page بسيط، سيتطلب تعيين أبعاده بشكل صحيح قبل أن يظهر. بعبارة أخرى: في الصفحة القابلة للتمرير أعلاه، anchors.fill: parent غير مطلوب؛ إذا تم استخدام صفحة بسيطة، فسيكون مطلوبًا.

هناك عروض متعددة يمكن استخدامها من واجهات برمجة التطبيقات، بعضها من كيوتي وبعضها من كيريغامي. إليك الأكثر استخدامًا:

أما المفوض فدائمًا ما يحتاج إلى ضبط أبعاده. عمومًا تُضبط أبعاده لاستخدام العرض الكامل للمنظر فقط.

الاستخدام الأكثر شيوعًا للمفوض يكون ضمن Component، الذي لا يُنشئ المفوض فورًا. عند بناء منظر، يُستخدم المفوض بعدها كمخطط لصنع كل عنصر في المنظر.

بينما يمكنك صنع مكوناتك المخصصة لاستخدامها كمفوضين دون واجهات برمجة تطبيقات كيو تي الخاصة بالمفوضين (مثلًا، تخطيط يحتوي على بضعة عناصر)، توفر عناصر تحكم كويك كيو تي واجهات برمجة تطبيقات للمفوضين يسهل استخدامها:

ينبغي تفضيل استخدام مفوضات كيو تي الأصلية حيثما أمكن.

فوق مفوضات كيو تي هذه، يوفر كيريغامي مكافئاتها الخاصة، مع وظائف إضافية للعناوين الفرعية والأيقونات:

يمكن ضبط واجهة البرمجة المنتهية بـ "Delegate" كمفوض مباشر للمنظر، تمامًا مثل الأمثلة السابقة التي استخدمت Controls.ItemDelegate:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami
import org.kde.kirigami.delegates as KD

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            KD.CheckSubtitleDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target}.`
                subtitle: `This delegate is stored at index ${model.index} of this list`
                icon.name: "kde"
            }
        }
    }
}

من المتوقع استخدام كل من TitleSubtitle وIconTitleSubtitle لتجاوز contentItem الخاص بمفوض كيو تي، على سبيل المثال:

import QtQuick
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami
import org.kde.kirigami.delegates as KD

Kirigami.ApplicationWindow {
    title: "List of Plasma products"
    width: 600
    height: 400
    pageStack.initialPage: Kirigami.ScrollablePage {
        ListView {
            // anchors.fill: parent
            model: plasmaProductsModel
            delegate: listDelegate
        }
        ListModel {
            id: plasmaProductsModel
            ListElement { product: "Plasma Desktop"; target: "desktop" }
            ListElement { product: "Plasma Mobile";  target: "mobile" }
            ListElement { product: "Plasma Bigscreen"; target: "TVs" }
        }
        Component {
            id: listDelegate
            Controls.ItemDelegate {
                width: ListView.view.width
                text: `${model.product} is KDE software developed for ${model.target}.`
                contentItem: KD.IconTitleSubtitle {
                    title: parent.text
                    subtitle: `This delegate is stored at index ${model.index} of this list`
                    icon.name: "kde"
                }
            }
        }
    }
}

يمكن رؤية مثال عملي لاستخدام مفوضات كيريغامي في ملف ListItemTest في مستودع كيريغامي.