PyQt和QML - 如何创建自定义数据模型

时间:2010-11-29 12:10:46

标签: python qt pyqt qml

如何在PyQt中创建QAbstractListModel并将其与QML ListView一起使用?

3 个答案:

答案 0 :(得分:1)

您需要设置它的角色名称才能在QML中使用它;

http://doc.qt.io/qt-4.8/qabstractitemmodel.html#setRoleNames

答案 1 :(得分:1)

没有使用过PyQT,但你可以在这里找到一个最小的工作样本:http://doc.qt.nokia.com/stable/qdeclarativemodels.html

如果您检查包含class Animal {...}的示例,您将看到必须为要提供的不同字段定义角色。至少,您必须定义data()函数,返回给定索引的相应字段值。此外,您可能需要自己的自定义方法来插入和删除。希望这会有所帮助...

答案 2 :(得分:0)

如果其他人正在寻找答案,我制作了一个小型应用程序,它连接到具有QAbstractListModel子类的actor数据库,并根据示例@fgungor发布在QGridView中显示缩略图。(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
                }


        }
    }
}