QAbstractItemModel은 C++로 구현된 모델을 QML에서 참조 할 수 있는 좋은 방법이다. 즉, QAbstractItemModel의 서브 클래스는 QML의 Model View (ListView, GridView, Repeater등과 같은) 에서 사용될 수 있다. C++ 데이터 세트 조작 방법은 성능에 큰 영향을 미치지 않고 QML UI 또는 뷰를 업데이트 할 수 있다.
QAbstractListModel은 추상 클래스이므로 인터페이스를 준수하도록 사용자가 구현해야한다. 다음과 같은 몇가지를 구현해줘야한다.
int rowCount();
QVariant data();
QHash<int, QByteArray> roleNames();
rowCount :
이 method는 단순히 데이터 세트이므로 m_data의 아이템 수를 반환한다.
int MyDataModel::rowCount(const QModelIndex &p) const
{
Q_UNUSED(p)
return m_data.size();
}
roleNames :
이 method는 사용자 정의 role enum을 key로 문자열 값을 매핑하고 매핑된 QHash를 리턴한다. roleNames() 메소드에 대한 호출이 될때 맵을 유지하기위해 정적 QHash 변수를 사용한다.
QHash<int, QByteArray> MyDataModel::roleNames() const
{
static QHash<int, QByteArray> roles;
roles[TitleRole] = "title";
roles[ArtistNameRole] = "artistName";
roles[DurationRole] = "duration";
return roles;
}
data :
이 method는 모델을 참조하는 ListView가 개별 아이템 및 속성에 액세스 할 수있는 방법이다. 인수 index는 목록에있는 요소의 인덱스이고 role은 roleNames 메소드로 매핑된 열거형 값이다.
구현은 단순히 데이터를 저장하는 m_data 목록의 인덱스에서 항목을 반환하는 것이다.
QVariant MyDataModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(role)
QVariant value;
switch(role)
{
case TitleRole:
value = m_data[index.row()]->property("title");
break;
case ArtistNameRole:
value = m_data[index.row()]->property("artistName");
break;
case DurationRole:
value = m_data[index.row()]->property("duration");
break;
default:
break;
}
return value;
}
추가로 이 모델에 count속성(Q_PROPERTY)을 추가한다.
Q_PROPERTY(int count READ count NOTIFY countChanged)
그리고 데이터를 세트를 조작 할 수 있는 다음과 같은 Method들도 필요 할 것이다.
void append(QObject *o);
void insert(QObject *o, int i);
void remove (int idx);
mymodel.h
#include <QAbstractListModel>
class MyDataModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
public:
enum ModelRoles {
TitleRole = Qt::UserRole + 1,
ArtistNameRole,
DurationRole
};
explicit MyDataModel(QObject * parent = nullptr);
int rowCount(const QModelIndex &p) const;
QVariant data(const QModelIndex &index, int role) const;
QHash<int, QByteArray> roleNames() const;
int count() const;
public slots:
void append(QObject *o);
void insert(QObject *o, int i);
void remove (int idx);
signals:
void countChanged(int count);
private:
QList<QObject*> m_data;
};
다음은 새로 서브클래싱한 모델의 사용밥법을 보여준다.
main.cpp
QQmlApplicationEngine engine;
// QAbstractListModel 서브클래싱 모델 객체 생성.
MyDataModel *model = new MyDataModel();
// 모델 아이템 생성.
QObject * item0 = new QObject();
item0->setProperty("title", "There's Nothing Holdin' Me Back");
item0->setProperty("artistName", "Shawn Mendes");
QObject * item1 = new QObject();
item1->setProperty("title", "Shape of You");
item1->setProperty("artistName", "Ed Sheeran");
//~ 모델 아이템 생성.
// 모델에 아이템 삽입.
model->append(item0);
model->append(item1);
//~ 모델에 아이템 삽입.
engine.rootContext()->setContextProperty("myModel", model);
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListView{
id: list_
anchors.fill: parent
model: myModel
delegate: Component{
Text{
anchors.horizontalCenter: parent.horizontalCenter
height: 30
font.bold: true
text: title + " - " + artistName
}
}
}
}