0

我正在尝试通过调用从 C++设置modelQML 的属性。GridView
QQmlProperty::write(gridview, "model", QVariant::fromValue(objlist));

gridview设置正确,我可以从 C++ 修改属性,当我将其设置为具有 6 个条目的 QList 并从我得到的 QML 打印它们时
qml: model = item(0x30617b50), Item(0x30617b90), Item(0x30617bd0), Item(0x30617c10), Item(0x30617c50), Item(0x30617cd0),尽管没有显示模型。

Qt 文档建议调用

QQmlContext *ctxt = view->rootContext(); ctxt->setContextProperty("gridModel", QVariant::fromValue(objlist));

然后使用 QML 设置属性,model: gridModel但这并不真正适合我的需要。它工作正常,只要设置了属性,就会显示正确的数据。当我从 QML 打印变量时,输出是
qml: model = [object Object]设置上下文属性和设置对象属性之间肯定存在差异,但我不知道如何解决这个问题。

4

3 回答 3

1

我建议不要尝试从 C++ 访问 QML 对象或属性,而是在 QML 端使用绑定并从 C++ 提供属性值。

如果通过 setContextProperty 公开模型实例不太符合您的需求,例如,如果模型是在 QML 加载时间之后实例化的,那么我建议采用以下方法:

  1. 通过 setContextProperty() 公开 QObject 派生类的实例,我
  2. 该类为您的模型获取 Q_PROPERTY,包括 NOTIFY 信号
  3. 在 QML 中,您将该属性绑定到 GridView 的模型
  4. 每当您在 C++ 中创建模型或需要创建模型的新实例时,都会发出上述 NOTIFY 信号

接口类看起来有点像这样

class MyInterface : public QObject
{
    Q_OBJECT
    Q_PROPERTY(MyModel* model READ model NOTIFY modelChanged)

public:
    MyModel *model() const { return m_model; }

    void setModel(MyModel *model) {
        m_model = model;
        emit modelChanged();
    }

private:
    MyModel *m_model = 0;
};

当然,m_model 的更改可以在 MyInterface 等内部进行,而不是 setter。这使您可以在 C++ 端完全控制何时创建模型实例、何时更改它、何时删除它。如果您将类型更改为 QAbstractItemModel* 或您的某些通用模型基类,您甚至可以在运行时根据需要更改模型的类型

于 2016-09-21T20:03:07.357 回答
0

我提出的解决方案与发布的答案略有不同,所以我认为最好写一个明确的答案。

关键是子类化QAbstractItemModel(或者更准确地说..ListModel,这样您就不必处理 C++QML 中的行/列)。

这样做时,您不仅可以简单地将模型设置为属性

QQuickItem *mainform = view->rootObject();
QQuickItem *grid = (QQuickItem *)mainform->findChild<QObject*>("GridView object name");

ItemModel itemmodel;
itemmodel.setItems(objlist):

QQmlProperty::write(grid, "model", QVariant::fromValue(&itemmodel));

每当对模型进行更改时,它也会通知 QML,例如删除项目。(不过,您必须正确处理更改,请参见removeRows()示例)

这是我的项目模型:

// itemmodel.h

#include <QAbstractListModel>
#include <item.h>

class ItemModel : public QAbstractListModel
{
    Q_OBJECT
public:
    explicit ItemModel(QObject *parent = 0);
    QHash<int, QByteArray> roleNames() const;

public slots:
    void setItems(QList<Item *> items);
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
    int rowCount(const QModelIndex & parent = QModelIndex()) const;
    bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());

private:
    QList<Item *> items;
};

// itemmodel.cpp
#include "itemmodel.h"

ItemModel::ItemModel(QObject *parent) : QAbstractListModel(parent)
{

}

// Column Names have to match all the Q_PROPERTYs defined in Item
const char* COLUMN_NAMES[] = {
    "property1",
    "property2",
    "...",
    NULL
};
QHash<int, QByteArray> makeRoleNames()
{
    int idx = 0;
    QHash<int, QByteArray> roleNames;
    while(COLUMN_NAMES[idx])
        roleNames[Qt::UserRole + idx + 1] = COLUMN_NAMES[idx++];

    return roleNames;
}

QHash<int, QByteArray> ItemModel::roleNames() const
{
    static const QHash<int, QByteArray> roleNames = makeRoleNames();
    return roleNames;
}

void ItemModel::setItems(QList<Item *> items)
{
    this->items = items;
}

int ItemModel::rowCount(const QModelIndex & /* parent */) const
{
    return items.count();
}

bool ItemModel::removeRows(int row, int count, const QModelIndex &parent)
{
    Q_UNUSED(parent);
    beginRemoveRows(QModelIndex(), row, row + count - 1);
    while (count--) delete items.takeAt(row);
    // example for custom deletion:
    //              items.takeAt(row)->removeFromRoot();
    endRemoveRows();
    return true;
}

QVariant ItemModel::data(const QModelIndex &index, int role) const {
    if (!index.isValid())
        return QVariant();

    if (index.row() >= items.size() || index.row() < 0)
        return QVariant();

    if (role == Qt::DisplayRole) {
        return QVariant::fromValue(this->items.at(index.row()));
    }

    if (role > Qt::UserRole)
        return this->items.at(index.row())->property(makeRoleNames()[role]);
}

资料来源:

  • [1]关于为 QML 创建 QAbstractItemModel 子类的 Qt 文档页面
  • [2] QAbstractItemModel 参考
  • [3] QAbstractItemModel 子类化指南
  • [4]带有 QAbstractListModel 子类的论坛帖子
  • [5] QAbstractItemModel 的工作(几乎data()略有改动)实现,我从中获取了角色名称函数
于 2016-09-23T06:54:04.477 回答
0

如果您说QQmlProperty::write正确设置了模型,那么您的问题是什么?无论如何,我建议另一种解决方案:

假设您有GridView以下内容:

GridView {
    anchors.fill: parent
    objectName: "grid"
    delegate: Rectangle {
        id: rect
        width: 100;
        height: 100
        color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
        Text {
            anchors.centerIn: rect
            text: modelData
        }
    }
}

objectName是强制性的。

所以从 C++ 访问可能是:

QStringList list;
list.append("String1");
list.append("String2");
list.append("String3");

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

QObject *obj = engine.rootObjects()[0]->findChild<QObject *>("grid");
if(obj) {
    obj->setProperty("model",QVariant(list));
}
于 2016-09-20T12:51:06.723 回答