从 QML 访问 C++ QList

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14287252/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:11:33  来源:igfitidea点击:

Accessing C++ QLists from QML

c++qmlqt5qlistqtquick2

提问by Timmmm

If I've got a list of things in C++, how do I expose that to QML (in Qt5 / QtQuick 2)? It seems like QML can only understand QObject-derived classes, which is an issue because QObjects can't be put in a QListor copied. How do I do this:

如果我在 C++ 中有一个列表,我如何将它公开给 QML(在 Qt5/QtQuick 2 中)?似乎 QML 只能理解 -QObject派生类,这是一个问题,因为QObjects 不能放入 aQList或复制。我该怎么做呢:

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;

    // ...

};

So that I can do something like this in QML:?

这样我就可以在 QML 中做这样的事情:?

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

采纳答案by Timmmm

After more experience with QML I've found the best way to have lists of things is with a QAbstractListModel.

在对 QML 有了更多经验之后,我发现拥有事物列表的最佳方法是使用QAbstractListModel.

You make your Thingderive from QObjectso it can be stored in a QVariant(after registering it). Then you can return the actual Thingas the model item. You can access it in a Repeateras model.display.a_property_of_thing. The list length is available as model.count.

你让你的Thing派生自,QObject所以它可以存储在一个QVariant(注册后)。然后您可以返回实际Thing作为模型项目。您可以在Repeateras 中访问它model.display.a_property_of_thing。列表长度可用作model.count.

This has the following pros and cons:

这有以下优点和缺点:

  1. Fast - it doesn't copy the entire list to access one element.
  2. You can easily get animations for changes to the list (addition, rearrangement and removal of items).
  3. It's easy to use from QML.
  4. To enable the animations to work, whenever you change the list you have to do some slightly faffy bookkeeping (beginInsertRows()etc.)
  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];
}

回答by Dickson

Alternatively, You can use QVariantList(QList<QVariant>), it will automatically change to JavaScript array when passed to QML, and it is read and write-able from C++ and QML

或者,您可以使用QVariantList( QList<QVariant>),它在传递给 QML 时会自动更改为 JavaScript 数组,并且可以从 C++ 和 QML 读取和写入

回答by eatyourgreens

I came across this question while trying to fix a similar problem, where I wanted to use C++ code as a model source in QML. The answer given by TheBootroo pointed me in the right direction, but did not work fully for me. I do not have enough reputation to answer him directly (but I did upvote his answer).

我在尝试解决类似问题时遇到了这个问题,我想在 QML 中使用 C++ 代码作为模型源。TheBootoo 给出的答案为我指明了正确的方向,但并不完全适合我。我没有足够的声誉来直接回答他(但我确实赞成他的回答)。

I am using Qt 5.0.0 I found this linkvery helpful

我正在使用 Qt 5.0.0 我发现这个链接非常有帮助

The definition of ThingManager should be changed as follows

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;
};

Note that I changed the return type of getThings to a QList<QObject*>. Without this change, Qt warns that it is "Unable to handle unregistered datatype 'QList<Thing*>'".

请注意,我将 getThings 的返回类型更改为 QList<QObject*>。如果没有此更改,Qt 会警告它“无法处理未注册的数据类型 'QList<Thing*>'”。

In the QML code, the properties of Thing can be accessed through the model as model.modelData.size and model.modelData.name.

在 QML 代码中,可以通过模型访问 Thing 的属性,如 model.modelData.size 和 model.modelData.name。

回答by Timmmm

Ah I found the answer (I think, not tested): QQmlListProperty

啊我找到了答案(我认为,未测试): QQmlListProperty

There's a few uses in the examples, e.g. at qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*:

示例中有一些用途,例如qtdeclarative/examples/quick/tutorials/gettingStartedQml/filedialog/directory.*

Unfortunately you can only have read-only lists at the moment.

不幸的是,您目前只能拥有只读列表。

回答by TheBootroo

you are quite wrong about QObject, they can be given to a QList, simply in the form of a pointer, as following works perfectly :

您对 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;
};

回答by Golil

best way use QQmlListProperty.see this simple sample , i hope help you.
Object and List Property Types Example

最好的方法是使用 QQmlListProperty 。看到这个简单的例子,我希望对你有帮助。
对象和列表属性类型示例

回答by Mr.Coffee

The answer given by eatyourgreensis correct. By implementing your class in that way you can access as many descendants as you want. One more helpful tip I found useful is to create an alias for our model inside the qml delegate element.

给出的答案eatyourgreens是正确的。通过以这种方式实现您的类,您可以访问任意数量的后代。我发现一个更有用的技巧是在 qml 委托元素中为我们的模型创建一个别名。

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

And then in the ItemDelegate.qml you can create alias for the model to not use all the time the model.modelData

然后在 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
        }
    }
}

回答by fokhagyma

Exist a good, but doesn't mentioned solution:

存在一个很好但没有提到的解决方案:

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;
// ...

};

Read and write are applicable. No expensive function call and data copy. Just direct access to the class members in QML:

读写都适用。没有昂贵的函数调用和数据复制。直接访问 QML 中的类成员:

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

For more info, see the doc: https://doc-snapshots.qt.io/qt5-dev/properties.html

有关更多信息,请参阅文档:https: //doc-snapshots.qt.io/qt5-dev/properties.html

回答by Amit Tomar

One highly indirect way of achieving it is this:

实现它的一种高度间接的方法是:

i.) Make a model in qml

i.) 在 qml 中创建模型

ListModel 
{
     id: thingModel

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

ii.) Then provide a couple javascript functions to modify this list eg.

ii.) 然后提供几个 javascript 函数来修改这个列表,例如。

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

function jClearThing()
{
    thingModel.clear()
}

similarly jDeleteThing etc..

类似 jDeleteThing 等。

iii.) You can read about how to call qml functions from c++

iii.) 您可以阅读有关如何从 C++ 调用 qml 函数的信息

iv.) Run a loop on your C++ list and call the append function of qml to add all that data into qml list as well.

iv.) 在 C++ 列表上运行一个循环并调用 qml 的 append 函数将所有数据也添加到 qml 列表中。

v.) On any update in C++ side list, modify the qml data as well using the above function to keep it updated.

v.) 在 C++ 侧列表中的任何更新中,使用上述函数修改 qml 数据以使其保持更新。