PyQt and QML - How can I create a custom data model
How should I create a QAbstractListModel in PyQt and use it开发者_开发问答 with a QML ListView?
If someone else is looking for an answer, I made a small app that connects to a database of actors with with a subclass of QAbstractListModel and displays the thumbnails in QGridView based on the example @fgungor posted.(PyQt5)
main.py:
import sys, models
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtQuick import QQuickView
if __name__ == '__main__':
# Prints QML errors
def handleStatusChange(status):
if status == QQuickView.Error:
errors = appLabel.errors()
if errors:
print (errors[0].description())
myApp = QApplication(sys.argv)
appLabel = QQuickView()
appLabel.statusChanged.connect(handleStatusChange)
model = models.ActorModel(DB_PATH)
ctxt = appLabel.rootContext()
ctxt.setContextProperty('myModel', model)
appLabel.setSource(QUrl('./qml/main/main.qml'))
try:
sys.exit(myApp.exec_())
except:
print("Exiting")
models.py:
import db
from PyQt5.QtCore import QAbstractListModel, Qt, pyqtSlot
class ActorModel(QAbstractListModel):
NameRole = Qt.UserRole + 1
ThumbRole = Qt.UserRole + 2
_roles = {NameRole: b"name", ThumbRole: b"thumb"}
def __init__(self, db_path):
super(ActorModel, self).__init__()
self._actors = []
self._db = db.Database(db_path)
def update(self, search_term):
self.beginResetModel()
self._actors = self._db.actor_search(search_term)
self.endResetModel()
# Reacts to onTextChanged event of searchBar (in QML code)
@pyqtSlot(str)
def search_input(self,search_input):
if len(search_input) > 3:
print (search_input)
self.update(search_input)
def rowCount(self, parent=None, *args, **kwargs):
return len(self._actors)
def data(self, QModelIndex, role=None):
row = QModelIndex.row()
if role == self.NameRole:
return self._actors[row]["name"]
if role == self.ThumbRole:
return self._actors[row]["thumbnail"]
def roleNames(self):
return self._roles
db.py:
import sqlite3
class Database:
def __init__(self, db_path):
self.db_path = db_path
self.sqlite_db = sqlite3.connect(self.db_path)
self.sqlite_db.row_factory = sqlite3.Row
self.cursor = self.sqlite_db.cursor()
def actor_search(self, actor_name):
self.cursor.execute('SELECT Actors.Id,Actors.Name,Actors.thumbnail AS thumbnail FROM Actors '
'WHERE Actors.Name LIKE \'%{}%\' ORDER BY Actors.Name'.format(actor_name))
return self.cursor.fetchall()
main.qml:
import QtQuick 2.8
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.1
Window {
id: root
visible: true
title: 'Actor Exploer'
width: 1280
height: 720
ColumnLayout {
id: mainLayout
anchors.fill: parent
Row {
Layout.fillWidth: true
TextArea {
id: searchBar
placeholderText: "Input actor name"
Layout.fillWidth: true
width: 600
onTextChanged: myModel.search_input(searchBar.text)
}
}
GridView {
id: gridView
keyNavigationWraps: true
Layout.fillWidth: true
Layout.fillHeight: true
cellWidth: 220
cellHeight: 320
model: myModel // QML connection to python model
delegate: Rectangle {
id: thumb_frame
height: 330
width: 200
Image {
id: actorThumb
asynchronous: true
source: "file:///" + thumb // Access to the ThumbRole in ActorModel in our python code
smooth: true
sourceSize.width: 200
sourceSize.height: 300
height: 300
width: 200
anchors.left: thumb_frame.left
anchors.top: thumb_frame.top
onStatusChanged: {
if (actorThumb.status == Image.Error)
actorThumb.source = 'PLACEHOLDER_IMAGE_PATH'
}
}
Text {
anchors.top: actorThumb.bottom
anchors.horizontalCenter: actorThumb.horizontalCenter
text: name // Access to the NameRole in ActorModel in our python code
}
}
}
}
You need to set it's role names to be able to use it in QML;
http://doc.qt.io/qt-4.8/qabstractitemmodel.html#setRoleNames
Haven't used PyQT but you can find a minimal working sample here: http://doc.qt.nokia.com/stable/qdeclarativemodels.html
If you inspect the sample including the class Animal {...}
you'll see that you have to define roles for the different fields you want to supply. And at a minimum you must define the data() function returning the corresponding field value for a given index. Also you'll need your own custom methods for inserting and removing possibly. Hope this helps...
精彩评论