Qt Quick 뷰에서 C++ 모델 사용
사용자 지정 C++ 모델에서 제공되는 데이터
모델을 C++로 정의한 다음 QML에서 사용할 수 있도록 만들 수 있습니다. 이는 기존 C++ 데이터 모델 또는 기타 복잡한 데이터 집합을 QML에 노출하는 데 유용합니다.
C++ 모델 클래스는 QStringList, QVariantList, QObjectList 또는 QAbstractItemModel 로 정의할 수 있습니다. 앞의 세 가지는 간단한 데이터 집합을 노출하는 데 유용하며, QAbstractItemModel 는 더 복잡한 모델을 위한 보다 유연한 솔루션을 제공합니다.
다음은 C++ 모델을 QML에 노출하는 전체 과정을 안내하는 동영상 튜토리얼입니다:
QStringList 기반 모델
모델은 modelData 역할을 통해 목록의 내용을 제공하는 간단한 QStringList 일 수 있습니다.
다음은 modelData
역할을 사용하여 모델 항목의 값을 참조하는 델리게이트가 있는 ListView 입니다:
ListView { width: 100 height: 100 required model delegate: Rectangle { required property string modelData height: 25 width: 100 Text { text: parent.modelData } } }
Qt 애플리케이션은 이 QML 문서를 로드하고 myModel
의 값을 QStringList 로 설정할 수 있습니다:
QStringList dataList = { "Item 1", "Item 2", "Item 3", "Item 4" }; QQuickView view; view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }});
이 예제의 전체 소스 코드는 Qt 설치 디렉터리 내의 examples/quick/models/stringlistmodel에서 확인할 수 있습니다.
참고: 뷰에서 QStringList 의 내용이 변경되었음을 알 수 있는 방법은 없습니다. QStringList 가 변경되면 뷰의 model
속성을 다시 설정하여 모델을 재설정해야 합니다.
QVariantList 기반 모델
모델은 modelData 역할을 통해 목록의 내용을 제공하는 단일 QVariantList 일 수 있습니다.
API는 이전 섹션에 표시된 것처럼 QStringList 와 동일하게 작동합니다.
참고: 뷰에서 QVariantList 의 콘텐츠가 변경되었음을 알 수 있는 방법은 없습니다. QVariantList 이 변경되면 모델을 재설정해야 합니다.
QObjectList 기반 모델
QObject* 값의 목록도 모델로 사용할 수 있습니다. QList <QObject*>는 목록에 있는 객체의 속성을 역할로 제공합니다.
다음 애플리케이션은 Q_PROPERTY 값이 포함된 DataObject
클래스를 생성하여 QList<DataObject*>가 QML에 노출될 때 명명된 역할로 액세스할 수 있도록 합니다:
class DataObject : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged) ... }; int main(int argc, char ** argv) { QGuiApplication app(argc, argv); const QStringList colorList = {"red", "green", "blue", "yellow"}; const QStringList moduleList = {"Core", "GUI", "Multimedia", "Multimedia Widgets", "Network", "QML", "Quick", "Quick Controls", "Quick Dialogs", "Quick Layouts", "Quick Test", "SQL", "Widgets", "3D", "Android Extras", "Bluetooth", "Concurrent", "D-Bus", "Gamepad", "Graphical Effects", "Help", "Image Formats", "Location", "Mac Extras", "NFC", "OpenGL", "Platform Headers", "Positioning", "Print Support", "Purchasing", "Quick Extras", "Quick Timeline", "Quick Widgets", "Remote Objects", "Script", "SCXML", "Script Tools", "Sensors", "Serial Bus", "Serial Port", "Speech", "SVG", "UI Tools", "WebEngine", "WebSockets", "WebView", "Windows Extras", "XML", "XML Patterns", "Charts", "Network Authorization", "Virtual Keyboard", "Quick 3D", "Quick WebGL"}; QList<QObject *> dataList; for (const QString &module : moduleList) dataList.append(new DataObject("Qt " + module, colorList.at(rand() % colorList.length()))); QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setInitialProperties({{ "model", QVariant::fromValue(dataList) }}); ...
QObject*는 modelData
속성으로 사용할 수 있습니다. 편의를 위해 델리게이트의 컨텍스트에서 객체의 프로퍼티를 직접 사용할 수도 있습니다. 여기서 view.qml
는 ListView 델리게이트의 DataModel
프로퍼티를 참조합니다:
ListView { id: listview width: 200; height: 320 required model ScrollBar.vertical: ScrollBar { } delegate: Rectangle { width: listview.width; height: 25 required color required property string name Text { text: parent.name } } }
color
프로퍼티의 사용에 유의하세요. 파생된 유형에서 기존 프로퍼티를 required
로 선언하여 요구할 수 있습니다.
이 예제의 전체 소스 코드는 Qt Quick 설치 디렉터리 내의 examples/quick/models/objectlistmodel에서 확인할 수 있습니다.
참고: 뷰에서는 QList 의 내용이 변경되었음을 알 수 있는 방법이 없습니다. QList 가 변경된 경우 model
속성을 다시 설정하여 모델을 재설정해야 합니다.
QAbstractItemModel 서브클래스
QAbstractItemModel 을 서브클래싱하여 모델을 정의할 수 있습니다. 다른 접근 방식으로는 지원할 수 없는 더 복잡한 모델이 있는 경우 이 방법이 가장 좋습니다. QAbstractItemModel 은 모델 데이터가 변경될 때 QML 뷰에 자동으로 알릴 수도 있습니다.
QAbstractItemModel 서브클래스의 역할은 QAbstractItemModel::roleNames()을 다시 구현하여 QML에 노출할 수 있습니다.
다음은 AnimalModel
이라는 이름의 QAbstractListModel 서브클래스가 있는 애플리케이션으로, 유형 및 크기 역할을 노출합니다. 이 애플리케이션은 QAbstractItemModel::roleNames()를 재구현하여 역할 이름을 노출하여 QML을 통해 액세스할 수 있도록 합니다:
class Animal { public: Animal(const QString &type, const QString &size); ... }; class AnimalModel : public QAbstractListModel { Q_OBJECT public: enum AnimalRoles { TypeRole = Qt::UserRole + 1, SizeRole }; AnimalModel(QObject *parent = nullptr); ... }; QHash<int, QByteArray> AnimalModel::roleNames() const { QHash<int, QByteArray> roles; roles[TypeRole] = "type"; roles[SizeRole] = "size"; return roles; } int main(int argc, char ** argv) { QGuiApplication app(argc, argv); AnimalModel model; model.addAnimal(Animal("Wolf", "Medium")); model.addAnimal(Animal("Polar bear", "Large")); model.addAnimal(Animal("Quoll", "Small")); QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); view.setInitialProperties({{"model", QVariant::fromValue(&model)}}); ...
이 모델은 유형 및 크기 역할에 액세스하는 ListView 델리게이트에 의해 표시됩니다:
ListView { width: 200; height: 250 required model delegate: Text { required property string type required property string size text: "Animal: " + type + ", " + size } }
모델이 변경되면 QML 보기가 자동으로 업데이트됩니다. 모델은 모델 변경에 대한 표준 규칙을 따라야 하며 QAbstractItemModel::dataChanged(), QAbstractItemModel::beginInsertRows() 등을 사용하여 모델이 변경된 경우 뷰에 알려야 합니다. 자세한 내용은 모델 서브클래싱 참조를 참조 하세요.
이 예제의 전체 소스 코드는 Qt 설치 디렉터리 내의 examples/quick/models/abstractitemmodel에서 확인할 수 있습니다.
QAbstractItemModel 은 테이블의 계층 구조를 표시하지만 현재 QML에서 제공하는 뷰는 목록 데이터만 표시할 수 있습니다. 계층적 모델의 하위 목록을 표시하려면 QAbstractItemModel 유형의 목록 모델에 사용할 수 있는 다음과 같은 프로퍼티와 함수를 제공하는 DelegateModel QML 유형을 사용하십시오:
- 노드에 자식 노드가 있는지 여부를 결정하는hasModelChildren 역할 속성.
- DelegateModel::rootIndex 루트 노드를 지정할 수 있습니다.
- DelegateModel::modelIndex()는 다음에 할당할 수 있는 QModelIndex 을 반환합니다. DelegateModel::rootIndex
- DelegateModel::parentModelIndex()는 다음에 할당할 수 있는 QModelIndex 을 반환합니다. DelegateModel::rootIndex
SQL 모델
Qt는 SQL 데이터 모델을 지원하는 C++ 클래스를 제공합니다. 이러한 클래스는 기본 SQL 데이터에서 투명하게 작동하므로 생성, 삽입 또는 업데이트와 같은 기본 SQL 작업에 대한 SQL 쿼리를 실행할 필요성을 줄여줍니다. 이러한 클래스에 대한 자세한 내용은 SQL 모델 클래스 사용을 참조하세요.
C++ 클래스는 SQL 데이터에서 작업할 수 있는 완전한 기능 세트를 제공하지만, QML에 대한 데이터 액세스는 제공하지 않습니다. 따라서 이러한 클래스 중 하나의 하위 클래스로 C++ 사용자 지정 데이터 모델을 구현하고 유형 또는 컨텍스트 속성으로 QML에 노출해야 합니다.
읽기 전용 데이터 모델
사용자 지정 모델은 QML에서 데이터에 읽기 전용으로 액세스할 수 있도록 다음 메서드를 다시 구현해야 합니다:
- roleNames()를 사용하여 역할 이름을 QML 프런트엔드에 노출합니다. 예를 들어, 다음 버전은 선택한 테이블의 필드 이름을 역할 이름으로 반환합니다:
QHash<int, QByteArray> SqlQueryModel::roleNames() const { QHash<int, QByteArray> roles; // record() returns an empty QSqlRecord for (int i = 0; i < this->record().count(); i ++) { roles.insert(Qt::UserRole + i + 1, record().fieldName(i).toUtf8()); } return roles; }
- data()를 사용하여 SQL 데이터를 QML 프런트엔드에 노출합니다. 예를 들어, 다음 구현은 주어진 모델 인덱스에 대한 데이터를 반환합니다:
QVariant SqlQueryModel::data(const QModelIndex &index, int role) const { QVariant value; if (index.isValid()) { if (role < Qt::UserRole) { value = QSqlQueryModel::data(index, role); } else { int columnIdx = role - Qt::UserRole - 1; QModelIndex modelIndex = this->index(index.row(), columnIdx); value = QSqlQueryModel::data(modelIndex, Qt::DisplayRole); } } return value; }
QSqlQueryModel 클래스는 SQL 데이터베이스의 데이터를 나타내는 사용자 지정 읽기 전용 모델을 구현하기에 충분합니다. 채팅 튜토리얼 예제에서는 SQLite 데이터베이스에서 연락처 세부 정보를 가져오는 사용자 지정 모델을 구현하여 이를 잘 보여줍니다.
편집 가능한 데이터 모델
QSqlTableModel 은 아래 설명된 대로 setData()를 구현합니다.
모델에서 사용하는 EditStrategy 에 따라 변경 사항은 나중에 제출하기 위해 대기열에 추가되거나 즉시 제출됩니다.
QSqlTableModel::insertRecord()를 호출하여 모델에 새 데이터를 삽입할 수도 있습니다. 다음 예제 코드 조각에서는 QSqlRecord 을 도서 세부 정보로 채우고 모델에 추가합니다:
... QSqlRecord newRecord = record(); newRecord.setValue("author", "John Grisham"); newRecord.setValue("booktitle", "The Litigators"); insertRecord(rowCount(), newRecord); ...
C++ 데이터 모델을 QML에 노출하기
위의 예에서는 뷰의 필수 속성을 사용하여 QML 구성 요소에서 직접 모델 값을 설정합니다. 이에 대한 대안으로 C++ 모델 클래스를 QML 유형으로 등록하는 방법도 있습니다( C++에서 QML 유형 정의 참조). 이렇게 하면 모델 클래스를 QML 내에서 유형으로 직접 만들 수 있습니다:
C++ | class MyModel : public QAbstractItemModel { Q_OBJECT QML_ELEMENT // [...] } |
QML | MyModel { id: myModel } |
C++에서 QML 유형을 작성하는 방법에 대한 자세한 내용은 C++로 QML 확장 작성하기를 참조하세요.
모델 데이터 변경
편집 가능한 모델은 roleNames()
및 data()
외에도 setData 메서드를 다시 구현하여 기존 모델 데이터의 변경 사항을 저장해야 합니다. 다음 버전의 메서드는 주어진 모델 인덱스가 유효한지, role
이 Qt::EditRole 과 같은지 확인합니다:
bool EditableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (index.isValid() && role == Qt::EditRole) { // Set data in model here. It can also be a good idea to check whether // the new value actually differs from the current value if (m_entries[index.row()] != value.toString()) { m_entries[index.row()] = value.toString(); emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole }); return true; } } return false; }
참고: 변경 사항을 저장한 후 dataChanged() 신호를 보내는 것이 중요합니다.
QListView 또는 QTableView 과 같은 C++ 항목 보기와 달리 setData()
메서드는 필요할 때마다 QML 델리게이트에서 명시적으로 호출해야 합니다. 이는 해당 모델 프로퍼티에 새 값을 할당하기만 하면 됩니다.
ListView { anchors.fill: parent model: EditableModel {} delegate: TextField { width: ListView.view.width text: model.edit onAccepted: model.edit = text } }
참고: edit
역할은 Qt::EditRole 과 동일합니다. 기본 제공 역할 이름은 roleNames()를 참조하세요. 그러나 실제 모델에서는 일반적으로 사용자 지정 역할을 등록합니다.
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.