Возврат пользовательского подкласса QObject из QAbstractListModel и использование его в ListView

Как я могу вернуть пользовательский подкласс QObject из QAbstractListModel и использовать его в QML ListView.

Я попытался вернуть объекты в качестве роли отображения и использую в своем qml display.property для доступа к свойствам, он работает нормально, но я видел, что в некоторых публикациях люди использовали модель как qobject из qml и обращались к свойствам как model.property. Я что-то пропустил?.

Другой вопрос: если я хочу выставить объект на уровне ListView и использовать его для установки какой-либо другой панели, такой как деталь основного вида, это выставить роль (в моем случае отображение) как вариантное свойство в делегате и установить его на уровень 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 ответа

Решение

Поскольку вы уже ответили на второй вопрос, позвольте мне ответить на первый вопрос, т.е. display.propertyName против model.propertyName

По сути, первая короткая рука для model.display.propertyNameт. е. осуществляется доступ к свойству "display" данных модели по заданному индексу. В вашем случае это возвращает объект, свойства которого включены.

model.propertyName также может быть написано просто propertyNameЭто означает, что метод data() модели вызывается с "ролью", являющейся числовым эквивалентом "propertyName".

Это отображение из "propertyName" в его числовой эквивалент делается с помощью QAbstractItemModel::roleNames() метод. Его реализация по умолчанию имеет несколько базовых отображений, таких как отображение "отображения" в Qt::DisplayRole,

Я немного поиграл с 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, мне нужно было просто объявить свойства в элементе делегата (свойство name типа string в данном примере), а затем связать свойство в ListView (selectedName в этом примере) с currentItem.property, таким образом, свойство в ListView будет обновляться автоматически, когда я выбираю другие элементы из списка, и у меня будет доступ к этим элементам из других элементов пользовательского интерфейса.

Другие вопросы по тегам