如何在QTableView中为单个单元格设置委托?

2024-09-30 18:28:42 发布

您现在位置:Python中文网/ 问答频道 /正文

类QTableView为setDelegate提供3个接口:

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

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

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

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

例如,我得到了一个包含两列的Qtableview,第一列设置了一个定制的QCombobox委托,其中包含了项目human和plant。第二列也使用QCombobox委托设置,但可选项取决于第一列的选择。这意味着第二列中的每个单元格可能有不同的委托

例如,如果从组合框委托中选择数据(行=1,列=1)作为人,则单元格(行=1,列=2)有一个组合框委托,其中包含项目标题、主体、手、脚;如果从组合框委托中将数据(行=2,列=1)选作植物,则单元格(行=2,列=2)有一个组合框委托,其项为根、叶、花

有一个类似的问题,但尚未得到回答,Set Delegate for each cell in a QTableView?


Tags: 数据项目标题主体humanplant委托qtableview
2条回答

至少(据我所知)PyQt5没有直接的解决方案

问题是,所有项目视图类都使用私有(并且从PyQt不可访问)^{}函数,该函数首先检查行并返回该行的委托(如果存在),然后对列执行相同的操作(如果存在),最后返回默认委托(内置委托或带有泛型属性的委托集)setItemDelegate()

因此,如果要确保委托始终首先基于行/列对(然后“退回”到某个依赖行或列的行为),唯一的解决方案是使用唯一的委托,然后根据行/列位置实现相关函数

我想你有一个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()

相关问题 更多 >