c++ - QML में उपयोग के लिए एक सामान्य वस्तु मॉडल कैसे बनाएं?



qt generics (1)

//Is this possible in any way?
//Q_PROPERTY(AnimalModel modelAnimals READ modelAnimals NOTIFY modelAnimalsChanged)

हाँ यह है, क्या आपने कोशिश नहीं की? बेशक, यह एक AnimalModel बल्कि एक AnimalModel * , लेकिन जब तक मॉडल QAbstractListModel विरासत में नहीं QAbstractListModel , तब तक आपको इसकी आवश्यकता है। परिवर्तन के रूप में आपको NOTIFY भाग की भी आवश्यकता नहीं है, मॉडल में आंतरिक रूप से वैसे भी स्वचालित रूप से परिलक्षित होगा। modelAnimalsChanged केवल तभी समझ में आता है जब आप पूरे मॉडल को एक अलग मॉडल के साथ बदलते हैं, और स्वाभाविक रूप से, एक सूचित संकेत के बिना एक संपत्ति का उपयोग करने के बारे में QML की चेतावनी को बंद करने के लिए। मॉडल ऑब्जेक्ट में परिवर्तन नहीं होने पर उत्तरार्द्ध करने के लिए एक क्लीनर तरीका बस एक स्लॉट या एक Q_INVOKABLE से एक AnimalModel * वापस Q_INVOKABLE

यदि आप वास्तव में लचीला मॉडल चाहते हैं, तो आप एक ऐसा स्टोर बना सकते हैं जो QObject * स्टोर QObject * , तो QML से आप मनमाने गुणों वाली मनमानी वस्तुएं बना सकते हैं, और मॉडल में जोड़ सकते हैं। तब मॉडल से आपके पास एक एकल object भूमिका होती है जो ऑब्जेक्ट को लौटाती है, और आप उस गुण को प्राप्त करने के लिए ऑब्जेक्ट को क्वेरी और उपयोग कर सकते हैं। जबकि "शास्त्रीय" सूची मॉडल कार्यान्वयन एक स्थिर, स्थिर स्कीमा के साथ एक मॉडल को परिभाषित करेगा, इस दृष्टिकोण का उपयोग करके विभिन्न गुणों के साथ मॉडल में "अनाकार" ऑब्जेक्ट होने की अनुमति देता है।

स्वाभाविक रूप से, इसके लिए कुछ प्रकार की सुरक्षा की आवश्यकता होती है, उदाहरण के लिए ऐसे मॉडल में प्रत्येक ऑब्जेक्ट के लिए एक property int type , और इसके आधार पर आप ऑब्जेक्ट के लिए उपलब्ध गुणों को निर्धारित कर सकते हैं। मेरे सामान्य दृष्टिकोण में एक प्रतिनिधि के लिए एक Loader , और क्या यह ऑब्जेक्ट को अलग-अलग QML UI कार्यान्वयन के डेटा स्रोत के रूप में पास करता है, जो उस वस्तु के प्रकार को दर्शाता है जो इसे तात्कालिक बनाता है। इस तरह आपके पास मॉडल में दोनों अलग-अलग ऑब्जेक्ट हैं, और अलग-अलग क्यूएमएल आइटम हैं जो प्रतिनिधि के रूप में हैं।

अंतिम "सभी ट्रेडों का जैक" सूची / मॉडल ऑब्जेक्ट बनाने के लिए QQmlListProperty और Q_CLASSINFO("DefaultProperty", "container") को लागू करना है, इसके लिए आपको सूची / मॉडल दोनों को गतिशील रूप से या QML की घोषणा का उपयोग करने की अनुमति है। वाक्य - विन्यास। यह भी ध्यान दें कि इस समाधान के साथ, आप ऐसे मॉडल से जोड़ या हटा सकते हैं, यहां तक ​​कि घोषित रूप से तात्कालिक वस्तुओं को भी हटा सकते हैं।

इसके अलावा, आपके उपयोग परिदृश्य के आधार पर, आपको मॉडल के लिए या तो qmlRegisterType() या qmlRegisterUncreatableType() हो सकता है।

ठीक है, दूसरी नज़र में, यह "किसी भी डेटा के मॉडल" जैसा दिखता है, जिसका मतलब है कि आप स्कीमा-कम मॉडल नहीं हैं, लेकिन बस अलग-अलग स्कीमा मॉडल हैं। उस स्थिति में, AnimalModel * को वापस करने के बजाय, आप QAbstractListModel * या यहां तक ​​कि QAbstractListModel * उपयोग कर सकते हैं - यह वैसे भी QML में काम करेगा, क्योंकि यह मेटा सिस्टम के माध्यम से गतिशीलता को नियोजित करता है। लेकिन किसी भी दर पर, स्कीमा-कम मॉडल बहुत अधिक शक्तिशाली और लचीले होते हैं, और उन्हें परिभाषित करने के लिए C ++ कोड की आवश्यकता नहीं होती है, यह सभी QML से अकेले काम कर सकते हैं।

class List : public QAbstractListModel {
    Q_OBJECT
    QList<QObject *> _data;

    Q_PROPERTY(int size READ size NOTIFY sizeChanged)
    Q_PROPERTY(QQmlListProperty<QObject> content READ content)
    Q_PROPERTY(QObject * parent READ parent WRITE setParent)
    Q_CLASSINFO("DefaultProperty", "content")
public:
    List(QObject *parent = 0) : QAbstractListModel(parent) { }
    int rowCount(const QModelIndex &p) const { Q_UNUSED(p) return _data.size(); }
    QVariant data(const QModelIndex &index, int role) const {
        Q_UNUSED(role)
        return QVariant::fromValue(_data[index.row()]);
    }
    QHash<int, QByteArray> roleNames() const {
        static QHash<int, QByteArray> * pHash;
        if (!pHash) {
            pHash = new QHash<int, QByteArray>;
            (*pHash)[Qt::UserRole + 1] = "object";
        }
        return *pHash;
    }
    int size() const { return _data.size(); }
    QQmlListProperty<QObject> content() { return QQmlListProperty<QObject>(this, _data); }

public slots:
    void add(QObject * o) {
        int i = _data.size();
        beginInsertRows(QModelIndex(), i, i);
        _data.append(o);
        o->setParent(this);
        sizeChanged();
        endInsertRows();
    }

    void insert(QObject * o, int i) {
        beginInsertRows(QModelIndex(), i, i);
        _data.insert(i, o);
        o->setParent(this);
        sizeChanged();
        endInsertRows();
    }

    QObject * take(int i) {
        if ((i > -1) && (i < _data.size())) {
            beginRemoveRows(QModelIndex(), i, i);
            QObject * o = _data.takeAt(i);
            o->setParent(0);
            sizeChanged();
            endRemoveRows();
            return o;
        } else qDebug() << "ERROR: take() failed - object out of bounds!";
        return 0;
    }

    QObject * get(int i) {
        if ((i > -1) && (i < _data.size())) return _data[i];
        else  qDebug() << "ERROR: get() failed - object out of bounds!";
        return 0;
    }

    void internalChange(QObject * o) { // added to force sort/filter reevaluation
      int i = _data.indexOf(o);
      if (i == -1) {
        qDebug() << "internal change failed, obj not found";
        return;
      } else {
        dataChanged(index(i), index(i));
      }
    }

signals:
    void sizeChanged();
};

फिर, आपके बाद qmlRegisterType<List>("Core", 1, 0, "List"); आप इसे किसी भी तरह से उपयोग कर सकते हैं, जिसे आप चाहते हैं - यह किसी भी QObject या व्युत्पन्न को धारण करेगा, स्वाभाविक रूप से QMLs QtObject सहित। इसे सीधे एक ListView ड्राइव करने के लिए एक मॉडल के रूप में उपयोग किया जा सकता है। आप इसे गतिशील रूप से स्लॉट या घोषणात्मक का उपयोग करके पॉप्युलेट कर सकते हैं, जैसे:

List {
    QtObject { ... }
    QtObject { ... }
    List {
        QtObject { ... }
        QtObject { ... }
    }
}

यह ऑब्जेक्ट के स्वामित्व को भी संभाल लेगा, और आप इसे आसानी से घोंसला बना सकते हैं, सार में एक कंपार्टमेंटलाइज़्ड ट्री मॉडल का उत्पादन कर सकते हैं - ध्यान दें कि आप घोषणात्मक रूप से क्यूएमएल की ListModel साथ ऐसा नहीं कर सकते। आप एक parentChanged सिग्नल जोड़ना चाहते हैं और एक सेटर लागू कर सकते हैं जो इसे बदलता है यदि आप एक बदलते माता-पिता के खिलाफ बांधना चाहते हैं, तो मेरे मामले में यह आवश्यक नहीं था।

दृश्य के साथ इसका उपयोग करने के तरीके के रूप में, आप या तो objectName उपयोग कर सकते हैं या एक अंतर int type संपत्ति या मूल रूप से विभिन्न ऑब्जेक्ट प्रकारों के बीच विचार करने के लिए कोई साधन, और प्रतिनिधि के लिए Loader उपयोग कर सकते हैं:

Loader {
    // using component in order to capture context props and present to the variable delegate
    sourceComponent: Qt.createComponent(obj.objectName + ".qml")
    // if that is not needed simply use
    // source: obj.objectName + ".qml"
    // or setSource to pass specific properties to delegate properties
    // Component.onCompleted: setSource(obj.objectName + ".qml", {/*prop list*/})
}

अपडेट करें:

यहाँ एक सरल और गतिशील और जेनेरिक सॉर्टिंग और फ़िल्टरिंग प्रॉक्सी के लिए कार्यान्वयन का सार भी इस मॉडल के साथ बढ़ाया प्रयोज्य के लिए जाना है।

मैं जानना चाहूंगा कि क्या QObject की संपत्ति के रूप में Qt मॉडल को पंजीकृत करने का कोई मैक्रो या तरीका है।

उदाहरण के लिए, मेरे पास AnimalModel ( http://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel ) है।

मुझे पता है कि मैं इसे QuickView के संदर्भ में पास कर सकता हूं

QuickView view;
view.rootContext()->setContextProperty("myModel", &model);

यदि मेरे पास QObject को Qml मैक्रोज़ के माध्यम से पंजीकृत किया गया है, तो मैं इस ऑब्जेक्ट को भी देखने के लिए पास कर सकता हूं:

view.rootContext()->setContextProperty("obj", pDataObject);

लेकिन क्या होगा अगर मैं QObject होना चाहता हूं जो किसी भी डेटा का मॉडल रखता है?

उदाहरण के लिए:

class DataObject : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
    ...

    AnimalModel m_modelAnimals;

    //Is this possible in any way?
    //Q_PROPERTY(AnimalModel modelAnimals READ modelAnimals NOTIFY modelAnimalsChanged)
};

हर उदाहरण जो मैंने अब तक पाया है कि QAbstractListModel को रूट संदर्भ में कैसे पास QAbstractListModel जाता है। लेकिन कोई नहीं इसे QObject प्रॉपर्टी के रूप में कैसे उपयोग किया जाए।

(मुझे पता है कि QQmlListProperty लेकिन QQmlListProperty आंशिक रूप से ताज़ा का समर्थन नहीं करती है। सभी Qml ऑब्जेक्ट्स को फिर से बनाना आवश्यक है)





qtquick2