从QAbstractListModel返回自定义QObject子类并在ListView中使用它

时间:2016-09-14 13:26:20

标签: qt listview qml qobject

如何从QAbstractListModel返回自定义QObject子类并在QML ListView中使用它。

我试图将对象作为显示角色返回,我在qml display.property中使用来访问属性,它工作正常但我在一些帖子中看到人们使用model作为qml的qobject并访问属性作为model.property。我错过了什么吗?。

另一个问题:如果我想在ListView级别公开对象并使用它来设置一些其他面板,如主视图细节,则将角色(在我的情况下显示)公开为委托和设置中的variant属性在listview级别使用onCurrentItemChanged信号是正确的方法吗?

这是我正在尝试的但它不起作用:

#ifndef NOTE_H
#define NOTE_H

#include <QObject>

class Note : public QObject
{
    Q_OBJECT

    Q_PROPERTY(QString note READ note WRITE setNote NOTIFY noteChanged)
    Q_PROPERTY(int id READ id WRITE setId NOTIFY idChanged)

    QString m_note;
    int m_id;

public:
    explicit Note(QObject *parent = 0);
    Note(QString note, int id, QObject *parent = 0);

    QString note() const
    {
        return m_note;
    }

    int id() const
    {
        return m_id;
    }

signals:

    void noteChanged(QString note);

    void idChanged(int id);

public slots:
    void setNote(QString note)
    {
        if (m_note == note)
            return;

        m_note = note;
        emit noteChanged(note);
    }
    void setId(int id)
    {
        if (m_id == id)
            return;

        m_id = id;
        emit idChanged(id);
    }
};

#endif // NOTE_H

视图模型:

#ifndef NOTESVIEWMODEL_H
#define NOTESVIEWMODEL_H

#include <QAbstractListModel>
#include <QVector>
#include "note.h"

class NotesViewModel : public QAbstractListModel
{
    Q_OBJECT

    QVector<Note*> notes;


public:
    NotesViewModel();

    QVariant data(const QModelIndex &index, int role) const override;
    int rowCount(const QModelIndex &parent) const override;

};

#endif // NOTESVIEWMODEL_H

视图模型的实现:

NotesViewModel::NotesViewModel()
{
    notes.append(new Note("note 1", 1));
    notes.append(new Note("note 2", 2));
    notes.append(new Note("note 3", 3));
    notes.append(new Note("note 4", 4));
    notes.append(new Note("note 5", 5));
}

QVariant NotesViewModel::data(const QModelIndex &index, int role) const
{
    qDebug() << "fetching data : " << index.row();
    if(!index.isValid()) return QVariant();
    if(index.row() >= 5) return QVariant();
    if(role == Qt::DisplayRole)
        return QVariant::fromValue(notes[index.row()]);
    return QVariant();
}

int NotesViewModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return notes.count();
}

2 个答案:

答案 0 :(得分:2)

由于您已经回答了第二个问题,请让我接受第一个问题,即display.propertyName vs model.propertyName

基本上第一个只是model.display.propertyName的简写,即&#34;显示&#34;正在访问给定索引处的模型数据的属性。在您的情况下,返回一个对象,该对象的on上有属性。

model.propertyName也可以写为propertyName,这意味着模型的数据()方法会被调用&#34; role&#34;是&#34; propertyName&#34;。

的数字等价物

来自&#34; propertyName&#34;的映射使用QAbstractItemModel::roleNames()方法完成其数值等效。 它的默认实现有一些基本映射,例如映射&#34; display&#34;到Qt::DisplayRole

答案 1 :(得分:1)

我使用qml ListView尝试了解如何将currentItem数据公开给外部世界。这就是我设法做到的方式,也许它会对像我这样的新手有用。

import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    ListModel {
        id: modell
        ListElement {
            fname: "houssem"
            age: 26
        }
        ListElement {
            fname: "Anna"
            age: 26
        }
        ListElement {
            fname: "Nicole"
            age: 26
        }
        ListElement {
            fname: "Adam"
            age: 27
        }
    }

    ListView {
        id: lv
        height: 100
        width: 200
        clip: true
        model: modell
        property string selectedName: currentItem.name
        delegate: Component {
            Item {
                id: mainItem
                width: ListView.view.width
                height: 80
                property string name: fname
                Text {
                    text: "name " + fname + " age " + age
                }
                MouseArea {
                    anchors.fill: parent
                    onClicked: mainItem.ListView.view.currentIndex = index
                }
            }
        }
    }
    Text {
        anchors.right: parent.right
        text: lv.selectedName
    }
}

正如您在代码中看到的那样,为了公开currentItem的数据,我只需要在委托Item中声明属性(在本示例中为string类型的name属性),然后绑定ListView上的属性(本例中为selectedName) )对于currentItem.property,这样当我从列表中选择其他项目时,ListView上的属性将自动更新,我将可以从UI的其他项目访问这些项目。