2016-02-02 11 views
5

QObjectのプロパティとしてQtモデルを登録する方法やマクロがあるかどうかを知りたいと思います。QMLで使用する汎用オブジェクトモデルを作成するにはどうすればよいですか?

たとえば、AnimalModelhttp://doc.qt.io/qt-5/qtquick-modelviewsdata-cppmodels.html#qabstractitemmodel)です。

は、私は私がQObjectのQMLマクロを経て登録されている場合は

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

クイックビュー

のルートコンテキストに渡すことができます知って、私はあまりにも表示するには、このオブジェクトを渡すことができます。

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アイテムがあります。

リスト/モデルを動的に作成したり、QMLの宣言構文を使用したりすることができるように、最終的な "すべての取引のジャック"リスト/モデルオブジェクトを作成する最後のステップは、QQmlListPropertyQ_CLASSINFO("DefaultProperty", "container")を実装することです。また、このソリューションでは、そのようなモデルを追加または削除したり、宣言的にインスタンス化されたオブジェクトを削除したりすることもできます。

また、ご使用のシナリオに応じて、モデルにはqmlRegisterType()またはqmlRegisterUncreatableType()のいずれかが必要です。

いいえ、2番目の一見では、スキーマレスモデルではなく単に異なるスキーマモデルを意味する "データのモデル"のように見えます。その場合、AnimalModel *を返す代わりにQAbstractListModel *、さらにはQObject *を使用することができます。メタシステムを使用してダイナミズムを使用するため、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; 
    } 
signals: 
    void sizeChanged(); 
}; 

、あなたはqmlRegisterType<List>("Core", 1, 0, "List");あなたはかなりあなたがしたい任意の方法を使用することができます後 - それは自然にそれが直接ListViewを駆動するためのモデルとして使用することができますQMLs QtObjectを含め、任意のQObjectまたは派生を保持しますが。あなたはこのように、スロットまたは宣言を使用して動的に取り込むことができます。

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

また、オブジェクトの所有権を処理すると、あなたが簡単に巣にそれをすることができ、本質的に区画され、ツリーモデルを作成 - あなたがいない宣言ことに注意してくださいQMLのListModelでそれを行います。 parentChangedシグナルを追加し、変化する親に対してバインドしたい場合は、それを発行するセッターを実装することができますが、私の場合はそうではありませんでした。あなたがobjectNameプロパティまたはint typeプロパティを使用して、デリゲートのためLoaderを使用することができますいずれかのビューでそれを使用する方法のよう

、:

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

オブジェクト名を使用する場合は、あなたが作りますローダーがname.qmlファイルを作成し、intを使用する場合はComponentの配列を作成し、適切なインデックスをソースコンポーネントとして使用できます。 objectLoaderのプロパティとして公開し、実際のオブジェクトUIにparent.object.propを参照させるか、またはsetSource(name + ".qml", {"object": object})を使用してオブジェクトのプロパティを直接その項目に入れることができます。setSourceはインラインComponentではなく外部ソースでのみ機能します。 s。外部ソースの場合、objectは何もせずに転送することができますが、何らかの理由でインラインコンポーネントでは機能しませんが、そのようなコンポーネントでは唯一可能な方法は、それをプロパティとして公開することですローダー。

+0

非常に複雑な答えをお寄せいただきありがとうございます。根本的な問題が無効な 'Q_PROPERTY'型であったということは間違いありませんでした。 'AnimalModel *'では素晴らしい動作をします。 'QObject *'のモデルに関して、これは私がすでに持っているものです(stackoverflow.com/questions/35065627/...)。しかし、あなたは 'Q_CLASSINFO'と' qmlRegisterType'ユースケースについて具体例を投稿したり、より具体的にしていただけますか?面白いようですが、私はこのケースでどのように正確に使用するのかよく分かりません。 –

+0

@LudekVodicka - 私はいくつかのコードを追加しました。同様の解決策を探している人がコードにアクセスしやすいように、質問のタイトルを変更する自由を取った。 – dtech

+0

これは絶対に傑作です。私は先月、Qmlを学んでいて、そのような素晴らしい方法で組み合わせることができないと思っていませんでした。説明と例をありがとう。私の心に唯一の質問です。静的ではなく静的なptrとしてQHashMapを使用するのはなぜですか?静的なQHash roles = {{ObjectRole、 "object}};'と定義することは可能ですが、C++ 11が必要です。これが理由でしたか? –

関連する問題