Возврат пользовательского подкласса 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 будет обновляться автоматически, когда я выбираю другие элементы из списка, и у меня будет доступ к этим элементам из других элементов пользовательского интерфейса.