首页 > 解决方案 > 带有 QML 和 PyQt 的项目列表

问题描述

我想创建一个简单的 GUI 元素列表,使用 PyQt + QML 方法排列在列表中。元素代表具有两个主要属性的项目:namestate。最初,该列表填充了一些代码内对象,例如来自 QT 设置存储。问题是,我想将从我的类(专用模块)的存储中检索到的每个条目包装起来。在伪代码中:

from my_module import Project

initial_list = [{
    name: 'Spaceship',
    state: 'In progress'
}, {
    name: 'Aircraft',
    state: 'Done'
}, {
    name: 'Truck',
    state: 'Broken'
}]

projects = [Project(p) for p in initial_list]

用户可以单击该项目并使用它执行一些任务(这就是我希望该元素成为Project实例的原因)。

我知道我应该有一个代表数据的模型,但我发现我发现的分散的例子很困难。我应该有单个元素的模型以及整个列表模型吗?如何将Project实例封装在QObject子类中?我最后的尝试是QAbstractListModel用作模型并ListView用作视觉表示。你能给我一个最小的完整例子吗?

标签: pythonlistviewpyqtqmlpyqt5

解决方案


猜猜我已经自己想通了。对于所有想要以某种方式重复该任务的人:您确实需要子类化QAbstractItemModel( QAbstractListModel) 以为您的 QML 提供模型(您不需要子类化单个项目,尽管我在有效情况下找到了方法)。

Python:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import sys

from PyQt5.QtCore import QCoreApplication, QUrl, QAbstractItemModel, pyqtProperty, QAbstractListModel, QModelIndex, \
    QObject, QVariant, Qt
from PyQt5.QtGui import QGuiApplication

from PyQt5.QtQuick import QQuickView

import mylib


class ProjectListItem(QObject):
    def __init__(self, project: mylib.Project, parent=None):
        super().__init__(parent)
        self.project = project

    @pyqtProperty('QString')
    def name(self):
        return self.project.path.name

    @pyqtProperty('QString')
    def state(self):
        return str(self.project.state)


class ProjectsList(QAbstractListModel):
    def __init__(self, projects: list, parent=None):
        super().__init__(parent)
        self.projects = projects

    def rowCount(self, parent=None, *args, **kwargs):
        return len(self.projects)

    def data(self, index: QModelIndex, role=None):
        # print(index, role)
        if role == Qt.DisplayRole:
            return self.projects[index.row()]

    def addProject(self, project):
        self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
        self.projects.append(project)
        self.endInsertRows()


if __name__ == '__main__':
    app = QGuiApplication(sys.argv)

    projects = ProjectsList([])
    projects.addProject(ProjectListItem(mylib.Project('Abc')))
    projects.addProject(ProjectListItem(mylib.Project('Def')))
    projects.addProject(ProjectListItem(mylib.Project('Ghi')))

    view = QQuickView()
    view.setResizeMode(QQuickView.SizeRootObjectToView)
    view.rootContext().setContextProperty('projectsModel', projects)
    view.setSource(QUrl('main.qml'))

    sys.exit(app.exec_())

QML:

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("PyQt5 love QML")
    color: "whitesmoke"

    GridLayout {
        columns: 2
        rows: 1

        ListView {
            width: 200; height: 250
            model: projectsModel
            delegate: Item {
                id: projectListItem
                width: ListView.view.width
                height: 40
                Column {
                    Text { text: '<b>Name:</b> ' + display.name }
                    Text { text: '<b>State:</b> ' + display.state }
                }
                MouseArea {
                    anchors.fill: parent
                    onClicked: { projectListItem.ListView.view.currentIndex = index; }
                }
            }
            highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
            focus: true
        }
    }
}

那么你会得到这样的东西:

在此处输入图像描述


推荐阅读