python - PyQt5 从模型中获取数据以在 QListView 中显示自定义小部件
问题描述
我正在使用 PyQt5 并尝试使用一些自定义数据结构 ( Recipe
) 的列表创建一个 GUI,并且我将自定义小部件定义为QWidget
描述它应该如何显示的子类。我正在尝试使用 MVC,所以我有一个QListView
子类QAbstractListModel
。我希望列表包含我的自定义小部件而不仅仅是文本,因此我还为其定义了一个返回该小部件的项目委托。也许我对这三个组件(模型、项目委托、视图)如何协同工作的理解存在缺陷,因为我不确定如何访问data()
模型方法返回的任何内容并将其转换为我想要的特定小部件显示在该列表单元格中。
示例代码:
class Recipe:
pass # custom data structure
class RecipeWidget(QWidget, RecipeWidgetUI):
def __init__(self, recipe, *args, **kwargs):
super(RecipeWidget, self).__init__(*args, **kwargs)
self.recipe = recipe
self.setupUi(self)
# some code here to populate the UI elements with data from self.recipe
class RecipeListModel(QAbstractListModel):
def __init__(self, recipes, *args, **kwargs):
super(RecipeListModel, self).__init__(*args, **kwargs)
self.recipes = recipes
def rowCount(self, index):
return len(self.recipes)
def data(self, index, role):
if role == Qt.DisplayRole:
return str(self.recipes[index.row()]) # this is the part I'm confused about
class RecipeItemDelegate(QItemDelegate):
def __init__(self, parent):
QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
return RecipeWidget(recipe, parent=parent) # where do I get recipe from??
class MainWindow(...):
def __init__(self, ...):
...
self.model = RecipeListModel(recipes)
self.listView.setModel(self.model)
self.listView.setItemDelegate(RecipeItemDelegate(self.listView))
我知道data(...)
模型中的函数应该返回一个字符串;我不明白的是:
- 我该如何返回我的
Recipe
数据结构?我是否必须以某种方式对其进行序列化,然后再反序列化? - 为了正确构造配方对象,在哪里可以
RecipeItemDelegate
看到函数返回的内容?data(...)
解决方案
- model.data() 需要为所需角色提供数据。在您的情况下,您可能决定使用 Qt.DisplayRole 来表示数据以供显示。你可以
return self.recipes[index.row()]
。但是如果要支持拖放,QT需要能够序列化数据。现在让我们在 self.recipes 中提供 python 索引,它可以被序列化。return index.row() # which happens to be python index in the self.recipes
- RecipeItemDelegate 需要能够使用来自 model.data() 的数据引用 Recipe 对象。所以,让我们初始化 RecipeItemDelegate(parent, parent.model().recipes)
- RecipeItemDelegate.paint(self,painter, option, index) 应被实施以绘制“显示”。在paint() 内部,index.data(Qt.DisplayRole) 获取配方中的数据行(恰好是index.row())。self.reference_to_recipes[index.data(Qt.DisplayRole)] 获取 Recipe 对象。然后你拿起“painter”,从你得到的数据中绘制信息,在“option”中指定区域和样式。另请参阅 QT 文档中的 QItemDelegate::paint。
如果您希望代理支持编辑,则:
- createEditor() 应该创建用于更改模型数据的小部件
- setEditorData() 应该使用要操作的数据填充小部件。喜欢
editor.set_recipe(self.reference_to_recipes[index.data(Qt.DisplayRole)])
- updateEditorGeometry() 确保编辑器相对于项目视图正确显示。
- setModelData() 将更新的数据返回给模型。当然, model.setData
model.setData(index, editor.get_modified_recipe(), Qt.EditRole)
() 需要能够在 Qt.EditRole 上处理 Recipe 对象
推荐阅读
- multithreading - 限制同时运行的线程数
- python - 比较 JSON 路径是否与索引等价
- logging - 声纳问题:确保此记录器的配置是安全的
- javascript - 如何找到嵌套在 JSON 中的列的最大值?
- c# - 列表中的所有项目都获得相同的值
- java - 从 Spring 项目中读取 Gitlab 的属性文件
- html - 如何在离子内容中滚动到底部
- ruby-on-rails - Websocket 仅适用于 ws:// 但不适用于 wss://
- django - 带有 Django 的 Amazon SES 不在 UTC 时区
- javascript - 使用 JavaScript 清除多选下拉菜单