在不设置Context的情况下从C ++设置GridView模型属性

时间:2016-09-20 11:50:11

标签: c++ qt qml qqmlcomponent

我试图通过调用
来从C ++设置QML model的{​​{1}}属性 GridView

QQmlProperty::write(gridview, "model", QVariant::fromValue(objlist));设置正确,我可以从C ++修改属性,当我将它设置为带有6个条目的QList并从QML打印出来时我得到了 gridview,虽然没有显示模型。

Qt文档建议调用

qml: model = item(0x30617b50), Item(0x30617b90), Item(0x30617bd0), Item(0x30617c10), Item(0x30617c50), Item(0x30617cd0)

然后使用QQmlContext *ctxt = view->rootContext(); ctxt->setContextProperty("gridModel", QVariant::fromValue(objlist));从QML设置属性,但这并不适合我的需要。它工作正常,只要设置了属性,就会显示正确的数据。当我从QML打印变量时,输出为
model: gridModel所以在设置context属性和设置object属性之间肯定存在差异,但我不知道如何解决这个问题。

3 个答案:

答案 0 :(得分:1)

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

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

  1. 通过setContextProperty(),i
  2. 公开QObject派生类的实例
  3. 该类为您的模型获取Q_PROPERTY,包括NOTIFY信号
  4. 在QML中将该属性绑定到GridView的模型
  5. 无论何时在C ++中创建模型,或者需要创建模型的新实例,都会发出上述NOTIFY信号
  6. 接口类看起来有点像

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

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

答案 1 :(得分: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));
}

答案 2 :(得分: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:

// 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]工作(几乎data()略有改动)QAbstractItemModel的实现,我从中获取了角色名称函数