【问题标题】:how to set a delegate for a single cell in QTableView?如何为 QTableView 中的单个单元格设置委托?
【发布时间】:2021-07-14 00:58:39
【问题描述】:

QTableView 类为 setDelegate 提供了 3 个接口:

  • setItemDelegate -- 为整个 QTableView 设置委托

  • setItemDelegateForRow -- 为给定行设置委托

  • setItemDelegateForColumn -- 为给定列设置委托

问题:如果我只想为一个单元格设置委托,我该怎么做?

例如,我有一个包含两列的 Qtableview,第一列设置有自定义 QCombobox 委托,其中包含人类和植物项目。第二列也设置了QCombobox委托,但可选项目取决于第一列的选择。这意味着第二列中的每个单元格可能有不同的代表。

例如,如果 data(row=1, col=1) 从组合框委托中选择为人类,则 cell(row=1, col=2) 有一个组合框委托,其中包含项目 header、body、hand、foot ;如果从组合框委托中选择 data(row=2, col=1) 作为植物,则 cell(row=2, col=2) 具有包含根、叶、花项的组合框委托。

有类似的问题,但还没有回答,Set Delegate for each cell in a QTableView?

【问题讨论】:

    标签: python pyqt5 qtableview


    【解决方案1】:

    我想你有一个XY problem。该逻辑与每个单元格的委托无关,而是实现基于 QModelIndex(提供行和列)的逻辑。

    import random
    import sys
    
    from PyQt5.QtCore import Qt
    from PyQt5.QtGui import QStandardItem, QStandardItemModel
    from PyQt5.QtWidgets import (
        QApplication,
        QComboBox,
        QStyledItemDelegate,
        QTableView,
        QWidget,
    )
    
    OPTIONS = {
        "human": ["header", "body", "hand", "foot"],
        "plant": ["root", "leaf", "flower"],
    }
    
    
    class Delegate(QStyledItemDelegate):
        def createEditor(self, parent, option, index):
            editor = QComboBox(parent)
            editor.currentTextChanged.connect(self.handle_commit_close_editor)
            return editor
    
        def setEditorData(self, editor, index):
            if index.column() == 0:
                option = index.data()
                editor.clear()
                editor.addItems(list(OPTIONS.keys()))
                editor.setCurrentText(option)
    
            elif index.column() == 1:
                option = index.sibling(index.row(), 0).data()
                options = OPTIONS.get(option, [])
                editor.clear()
                editor.addItems(options)
    
        def setModelData(self, editor, model, index):
            if index.column() == 0:
                option = editor.currentText()
                model.setData(index, option, Qt.DisplayRole)
                options = OPTIONS.get(option, [])
                model.setData(
                    index.sibling(index.row(), 1),
                    options[0] if options else "",
                    Qt.DisplayRole,
                )
            elif index.column() == 1:
                option = editor.currentText()
                model.setData(index, option, Qt.DisplayRole)
    
        def handle_commit_close_editor(self):
            editor = self.sender()
            if isinstance(editor, QWidget):
                self.commitData.emit(editor)
                self.closeEditor.emit(editor)
    
    
    def main():
        app = QApplication(sys.argv)
    
        app.setStyle("fusion")
    
        model = QStandardItemModel(0, 2)
    
        for i in range(4):
            option = random.choice(list(OPTIONS.keys()))
            item_1 = QStandardItem(option)
            item_2 = QStandardItem(random.choice(list(OPTIONS[option])))
            model.appendRow([item_1, item_2])
    
        view = QTableView()
        view.setModel(model)
        view.resize(640, 480)
        view.show()
    
        delegate = Delegate(view)
        view.setItemDelegate(delegate)
    
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        main()
    

    【讨论】:

    • 非常感谢,它对我有用。我尝试了另一种方法,但它不如这个。
    【解决方案2】:

    对此没有直接的解决方案,至少(据我所知)来自 PyQt5。

    问题是所有项目视图类都使用一个私有(并且无法从 PyQt 访问)delegateForIndex 函数,该函数首先检查行并返回该行的委托(如果存在),然后对列执行相同操作(同样,如果存在的话)并最终返回默认委托(内置委托或具有通用 setItemDelegate() 的集合)。

    因此,如果您想确保代理首先始终基于行/列对(然后“回退”到某些行或列相关行为),唯一的解决方案就是使用一个unique委托,然后根据行/列位置实现相关功能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-05
      • 2020-03-08
      • 2020-10-06
      相关资源
      最近更新 更多