web-dev-qa-db-ja.com

QMLからC ++ QListにアクセスする

C++で物事のリストを入手した場合、それをQML(Qt5/QtQuick 2)に公開するにはどうすればよいですか? QMLはQObject派生クラスしか理解できないようですが、これはQObjectsをQListに入れたりコピーしたりできないため問題です。どうすればよいですか。

struct Thing
{
    int size;
    QString name;
};

class ThingManager : public QObject
{
    Q_OBJECT

    // These macros support QtQuick, in case we one day want to use it to make a slick
    // interface (when QML desktop components are released).
    Q_PROPERTY(QList<Thing> things READ things NOTIFY thingssChanged)

public:
    // ...
    QList<Thing> things() const;

    // ...

};

QMLで次のようなことができるように:?

var a = thingManager.things[0].name;
28
Timmmm

QMLについてさらに経験を積んだ後、物事のリストを作成する最善の方法は QAbstractListModel を使用することです。

ThingQObjectから派生させ、QVariantに格納できるようにします(登録後)。次に、実際のThingをモデルアイテムとして返すことができます。 Repeaterで_model.display.a_property_of_thing_としてアクセスできます。リストの長さは_model.count_として利用できます。

これには次の長所と短所があります。

  1. 高速-1つの要素にアクセスするためにリスト全体をコピーしません。
  2. リストの変更(アイテムの追加、再配置、削除)のアニメーションを簡単に取得できます。
  3. QMLから簡単に使用できます。
  4. アニメーションが機能するようにするには、リストを変更するときはいつでも、少しおかしな簿記(beginInsertRows()など)を実行する必要があります

...

_class Things : public QObject
{
...
};

Q_DECLARE_METATYPE(Thing*)

class ThingList : public QAbstractListModel
{
    Q_OBJECT

public:
    explicit ThingList(QObject *parent = 0);
    ~ThingList();

    int rowCount(const QModelIndex& parent = QModelIndex()) const override;
    QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;

public slots:

    // Extra function to get the thing easily from outside Repeaters.
    Thing* thing(int idx);

private:
    QList<Thing*> mThings;
};

int ThingList::rowCount(const QModelIndex& parent) const
{
    return mThings.size();
}

QVariant ThingList::data(const QModelIndex& index, int role) const
{
    int i = index.row();
    if (i < 0 || i >= mPorts.size())
        return QVariant(QVariant::Invalid);

    return QVariant::fromValue(mThings[i]);
}

Thing* ThingList::thing(int idx)
{
    if (idx < 0 || idx >= mThings.size())
        return nullptr;

    return mThings[idx];
}
_
9
Timmmm

または、QVariantListQList<QVariant>)、QMLに渡されると自動的にJavaScript配列に変更され、C++およびQMLから読み取りおよび書き込み可能です

24
Dickson

QMLのモデルソースとしてC++コードを使用したいという同様の問題を修正しようとしたときに、この質問に出くわしました。 TheBootrooの答えは私を正しい方向に向かわせましたが、十分に機能しませんでした。私は彼に直接回答するのに十分な評判がありません(しかし私は彼の回答に賛成票を投じました)。

私はQt 5.0.0を使用しています このリンク 非常に役に立ちました

ThingManagerの定義を次のように変更する必要があります

class ThingManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<QObject*> things READ getThings NOTIFY thingsChanged)

public:
    QList<QObject*> getThings () const { return m_things; }

signals:
    void thingsChanged ();

private:
    QList<QObject*> m_things;
};

GetThingsの戻り値の型をQList <QObject *>に変更したことに注意してください。この変更がないと、Qtは「未登録のデータ型 'QList <Thing *>'を処理できません」と警告します。

QMLコードでは、Thingのプロパティはmodel.modelData.sizeおよびmodel.modelData.nameとしてモデルを介してアクセスできます。

22
eatyourgreens

ああ、私は答えを見つけました(私はテストしていません): QQmlListProperty

例にはいくつかの使用法があります。 qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*

残念ながら、現時点では読み取り専用のリストしか作成できません。

5
Timmmm

あなたはQObjectについてかなり間違っています、それらはQListに単純にポインタの形で与えることができます、以下は完全に機能します:

class Thing : public QObject
{
    Q_OBJECT

    Q_PROPERTY (int     size READ getSize CONSTANT)
    Q_PROPERTY (QString name READ getName CONSTANT)

public:
    Thing(QObject * parent = NULL) : QObject(parent) {}

    int     getSize () const { return m_size; }
    QString getName () const { return m_name; }

private:
    int     m_size;
    QString m_name;
};

class ThingManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QList<Thing*> things READ getThings NOTIFY thingsChanged)

public:
    QList<Thing*> getThings () const { return m_things; }

signals:
    void thingsChanged ();

private:
    QList<Things*> m_things;
};
3
TheBootroo

最善の方法 QQmlListProperty を使用してください。この簡単なサンプルを参照してください。
オブジェクトおよびリストプロパティタイプの例

2
Golil

eatyourgreensの答えは正しいです。この方法でクラスを実装することにより、必要な数の子孫にアクセスできます。さらに役立つヒントとして、qmlデリゲート要素内にモデルのエイリアスを作成します。

ListView {
   anchors.fill: parent
   model: thing_manager.things
   delegate: ItemDelagate {}
   clip: true
   spacing: 10
}

そして、ItemDelegate.qmlでモデルのエイリアスを作成して、常にmodel.modelDataを使用しないようにすることができます。

Item{
    width: 600
    height: 200
    property var thing: model.modelData
    Rectangle {
        anchors.fill: parent
        color: "red"
        Text {
            text: thing.name // or any other field
        }
    }
}
1
Mr.Coffee

それを達成する非常に間接的な方法の1つは次のとおりです。

i。)qmlでモデルを作成する

ListModel 
{
     id: thingModel

     ListElement 
     {
         size: 10
         name: "Apple"
     }     
}

ii。)次に、このリストを変更するためのJavaScript関数をいくつか提供します。

function jAppendThing( newSize, newName )
{
    thingModel.append({"size": nameSize, "name": newName })
}

function jClearThing()
{
    thingModel.clear()
}

同様にjDeleteThingなど。

iii。) c ++からqml関数を呼び出す方法について読むことができます

iv。)C++リストでループを実行し、qmlの追加関数を呼び出して、すべてのデータをqmlリストに追加します。

v。)C++サイドリストの更新時に、上記の関数を使用してqmlデータも変更し、更新を維持します。

0
Amit Tomar

良い存在ですが、解決策については触れていません:

class ThingManager : public QObject
{
Q_OBJECT

// These macros support QtQuick, in case we one day want to use it to make a slick
// interface (when QML desktop components are released).
Q_PROPERTY(QList<Thing> things MEMBER m_things NOTIFY thingssChanged)

// ...
private:
// ...
QList<Thing> m_things;
// ...

};

読み取りと書き込みが適用されます。高価な関数呼び出しとデータコピーは不要です。 QMLのクラスメンバーに直接アクセスするだけです。

var a = thingManager.things[0].name;

詳細については、ドキュメントを参照してください: https://doc-snapshots.qt.io/qt5-dev/properties.html

0
fokhagyma