簡體   English   中英

PyQt5 從 model 獲取數據以在 QListView 中顯示自定義小部件

[英]PyQt5 get data from model to show custom widget in QListView

我正在使用 PyQt5 並嘗試創建一個帶有一些自定義數據結構列表的 GUI ( Recipe ),並且我將自定義小部件定義為QWidget的子類,描述了它應該如何顯示。 我正在嘗試使用 MVC,所以我有一個QListView並且我對QAbstractListModel進行了子類化。 我希望列表包含我的自定義小部件而不僅僅是文本,因此我還為其定義了一個返回該小部件的項目委托。 也許我對這三個組件(模型、項目委托、視圖)如何協同工作的確切理解是有缺陷的,因為我不確定如何訪問從 model 的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))

我知道 model 中的data(...) function 應該返回一個字符串; 我不明白的是:

  • 我該如何返回我的Recipe數據結構? 我是否必須以某種方式序列化它然后再反序列化?
  • RecipeItemDelegate在哪里查看data(...) function 返回的內容,以便正確構建配方 object?

每個項目都可以根據角色保存多個數據屬性。 這些數據屬性是 QVariants。 您可以在 QVariant 中嵌入很多不同的東西,甚至是自定義對象。

我會說最好的做法是將字符串用於顯示角色,並將 Qt.UserRole(或 Qt.UserRole + n)用於其他用途。 您的委托人仍然可以通過在查詢項目數據時提供該角色來訪問這些內容。

盡管我使用 C++ 進行開發,但我並不精通如何將 QVariant 的自定義類型與 PyQt5 一起使用。請注意,如果您將 Qt 用於 Python 而不是 PyQt5,則無需使用 QVariant any,只需設置和獲取自定義 python 變量。

  1. 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
  2. RecipeItemDelegate 需要能夠使用 model.data() 中的數據引用配方 object。 所以,讓我們初始化 RecipeItemDelegate(parent, parent.model().recipes)
  3. 應實施 RecipeItemDelegate.paint(self, painter, option, index) 來繪制“顯示”。 在 paint() 內部,index.data(Qt.DisplayRole) 獲取數據 - 食譜中的行(恰好是 index.row())。 self.reference_to_recipes[index.data(Qt.DisplayRole)] 得到Recipe object。然后你選擇“painter”,根據你得到的數據繪制信息,在“option”指定的區域和樣式中。 另請參閱 QT 文檔中的 QItemDelegate::paint。

如果您希望代表支持編輯,則:

  1. createEditor() 應該創建用於更改 model 數據的小部件
  2. setEditorData() 應該用要操作的數據填充小部件。 editor.set_recipe(self.reference_to_recipes[index.data(Qt.DisplayRole)])
  3. updateEditorGeometry() 確保編輯器相對於項目視圖正確顯示。
  4. setModelData() 將更新后的數據返回到 model。例如model.setData(index, editor.get_modified_recipe(), Qt.EditRole)當然,model.setData() 需要能夠在 8488299540283838 上處理 Recipe 8828299540283838

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM