2016-02-02 15 views
5

मैं जानना चाहता हूं कि 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 पारित करने के लिए कैसे। लेकिन QObject संपत्ति के रूप में इसका उपयोग कैसे करें।

(मैं जानता हूँ कि वहाँ QQmlListProperty लेकिन QQmlListProperty आंशिक ताज़ा समर्थन नहीं करता। यह हमेशा सभी Qml वस्तुओं के पुनर्निर्माण के लिए आवश्यक है)

उत्तर

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

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

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

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

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

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

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

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; 
    } 
signals: 
    void sizeChanged(); 
}; 

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

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

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

कैसे एक दृश्य के साथ इसका इस्तेमाल करने के रूप में, आप objectName संपत्ति या एक int type संपत्ति उपयोग कर सकते हैं, और प्रतिनिधि के लिए एक Loader का उपयोग करें:

Loader { 
    width: childrenRect.width 
    height: childrenRect.height 
} 

आप ऑब्जेक्ट नाम का उपयोग करते हैं, तो आप कर लोडर name.qml फ़ाइल बनाते हैं, यदि आप int का उपयोग करते हैं, तो आप Component एस की सरणी बना सकते हैं और उपयुक्त घटक का उपयोग स्रोत घटक के रूप में कर सकते हैं। आप Loader की एक संपत्ति के रूप में object बेनकाब कर सकते हैं या तो और वास्तविक वस्तु यूआई यह parent.object.prop संदर्भ है, या आप setSource(name + ".qml", {"object": object}) का उपयोग करें और वस्तु संपत्ति है कि आइटम में सीधे हो सकता है, फिर भी setSource केवल, बाहरी स्रोतों के साथ काम करेंगे इनलाइन Component साथ नहीं रों। ध्यान दें कि बाहरी स्रोत के मामले में, object इसे आगे बढ़ाने के लिए कुछ भी किए बिना भी पहुंच योग्य होगा, हालांकि किसी कारण से यह इनलाइन घटकों के साथ काम नहीं करता है, ऐसे घटकों के साथ ही इसे एक संभावित संपत्ति के रूप में उजागर करना संभव है लोडर

+0

बहुत सारे रोचक विचारों के साथ बहुत ही जटिल उत्तर के लिए धन्यवाद। आप सही थे कि रूट समस्या अमान्य 'Q_PROPERTY' प्रकार में थी। 'AnimalModel *' के साथ यह बहुत अच्छा काम करता है। 'QObject * 'के मॉडल के संबंध में, यह मेरे पास पहले से कुछ है (stackoverflow.com/questions/35065627/...)। लेकिन क्या आप उदाहरण पोस्ट कर सकते हैं या 'Q_CLASSINFO' और' qmlRegisterType' उपयोग केस के बारे में अधिक विशिष्ट हो सकते हैं? यह दिलचस्प लगता है लेकिन मुझे यकीन नहीं है कि इस मामले में इसका उपयोग कैसे किया जाए। –

+0

@ लुडेकवोडिका - मैंने कुछ कोड जोड़ा, आपके प्रश्न को फिर से शीर्षक देने की स्वतंत्रता भी ली ताकि कोड उन लोगों के लिए अधिक सुलभ हो जो समान समाधान की तलाश में हैं। – dtech

+0

यह बिल्कुल उत्कृष्ट कृति है। मैं पिछले महीने और आधा क्यूएमएल सीख रहा हूं और मुझे नहीं पता था कि इसे इस तरह के महान तरीके से जोड़ा जा सकता है। स्पष्टीकरण और उदाहरणों के लिए धन्यवाद। एकमात्र सवाल जो मेरे दिमाग में आता है। QHashMap केवल स्थैतिक के बजाय स्थिर पीआरटी के रूप में क्यों? इसे 'स्थिर QHash भूमिकाएं {{{ऑब्जेक्ट रोल, "ऑब्जेक्ट"}} के रूप में परिभाषित करना संभव है; लेकिन इसे सी ++ 11 की आवश्यकता है। क्या यही कारण था? –

संबंधित मुद्दे