如何实现QML ListModel,就像QAbstractListModel派生模型的get方法一样

时间:2014-03-28 11:19:42

标签: qt qml qt-quick qtquick2 qabstractitemmodel

我想在QML中使用QAbstractListModel派生模型。将模型绑定到视图已经很有效。

我想要实现的下一件事是能够访问特定项目及其角色,就像使用QML ListModel一样

grid.model.get(index).DisplayRole

但是我不知道如何在我的QAbstractListModel派生模型中实现这个get方法。

任何提示?

5 个答案:

答案 0 :(得分:19)

您可以将Q_INVOKABLE函数添加到QAbstractItemModel派生类,如下所示:

...

Q_INVOKABLE QVariantMap get(int row);

...

QVariantMap get(int row) {
    QHash<int,QByteArray> names = roleNames();
    QHashIterator<int, QByteArray> i(names);
    QVariantMap res;
    while (i.hasNext()) {
        i.next();
        QModelIndex idx = index(row, 0);
        QVariant data = idx.data(i.key());
        res[i.value()] = data;
        //cout << i.key() << ": " << i.value() << endl;
    }
    return res;
}

这将返回类似{ "bookTitle" : QVariant("Bible"), "year" : QVariant(-2000) }的内容,因此您可以使用.bookTitle

答案 1 :(得分:12)

如果你想在列表模型中使用经典的角色方法,你不必在c ++方面做任何特别的事情,那么你总是有你的模型,它应该实现数据方法:

QVariant QAbstractItemModel::data(const QModelIndex & index, int role = Qt::DisplayRole) const

要从QML访问不同的角色,model附加属性可以在ListView委托中使用:

model.display // model.data(index, Qt::DisplayRole) in c++
model.decoration // Qt::DecorationRole
model.edit // Qt::EditRole
model.toolTip // Qt::ToolTipRole
// ... same for the other roles

我认为Qt doc中尚未记录任何内容,但是要找出可以通过QML访问哪些属性,只需在调试模式下启动应用程序并在代理中放置断点或打印所有控制台的属性。 Btw委托中的model属性是QQmlDMAbstractItemModelData类型,所以有一些&#34; Qt魔法&#34;发生在后台,看起来像列表模型数据的一些包装,我仍然在Qt文档中找不到任何关于它的官方文件(我自己用QML调试器和东西想出来)。

如果您需要从代表外部访问模型数据,我认为没有任何内置功能,所以您必须自己完成。

我为自定义QAbstractListModel类做了一个示例,该类公开了count属性和get - 类似于默认QML ListModel的函数:

mylistmodel.h

class MyListModel : public QAbstractListModel
{
    Q_OBJECT
    Q_PROPERTY(int count READ rowCount NOTIFY countChanged)

public:
    explicit MyListModel(QObject *parent = 0);

    int rowCount(const QModelIndex & = QModelIndex()) const override { return m_data.count(); }
    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;

    Q_INVOKABLE int get(int index) const { return m_data.at(index); }

signals:
    void countChanged(int c);

private:
    QList<int> m_data;
};

mylistmodel.cpp

MyListModel::MyListModel(QObject *parent) :
    QAbstractListModel(parent)
{
    m_data << 1 << 2 << 3 << 4 << 5; // test data
    emit countChanged(rowCount());
}

QVariant MyListModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() < 0 || index.row() >= rowCount())
        return QVariant();

    int val = m_data.at(index.row());

    switch (role) {
    case Qt::DisplayRole:
        return QString("data = %1").arg(val);
        break;
    case Qt::DecorationRole:
        return QColor(val & 0x1 ? Qt::red : Qt::green);
        break;
    case Qt::EditRole:
        return QString::number(val);
        break;
    default:
        return QVariant();
    }
}

由于向QML公开属性和函数非常容易,我想这是一个很好的方法来做知道。

为了完整性,这里有一个使用我的自定义模型的ListView示例:

ListView {
    anchors.fill: parent
    model: MyListModel { id: myModel }
    delegate: Text {
        text: model.display
    }

    Component.onCompleted: {
        console.log(myModel.count) // 5
        console.log(myModel.get(0)) // 1
    }
}

答案 2 :(得分:0)

我的方法是暴露物品&#39;属性直接到QML。这是它的实现 - https://stackoverflow.com/a/14424517/1059494

答案 3 :(得分:0)

这花了我很长时间才发现,因为Stackoverflow上有许多不正确的解决方案。

我在这里发布了回复:

How to access ListView's current item from qml

这适用于所有模型,无论是从QAbstractItemModel派生还是直接在QML中构建,甚至允许访问树形模型。

答案 4 :(得分:0)

执行此操作的另一种方法是直接使用QAbstractItemModel的内置函数,例如通过

grid.model.data(grid.model.index(index, 0), 0 /*== Qt::DisplayRole*/)

这在技术上有效,但要求用户知道角色的数字代码,而不是指定字符串。这里的主要问题是,最多只有内置功能来确定roleNames()。为了将名称字符串正确映射到相应的数值,需要实现反转函数并使用Q_INVOKABLE公开它,或者手动处理QML中QHash得到的roleNames()