如何将参数传递给 QStyledItemDelegate 的 createEditor 函数

How to pass a parameter to createEditor functions of QStyledItemDelegate

一个软件工具有一个 table 填充了两列:参数和数据。 “数据”列有组合框小部件。如何将 listData 作为参数传递给 createEditor 函数,我可以将 listCombo 分配给 listData?

import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtCore
import pandas as pd

class DataDelegate(QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        comboBox = QComboBox(parent)
        listCombo = []
        comboBox.addItems(listCombo)
        comboBox.setCurrentIndex(1)
        comboBox.currentTextChanged.connect(lambda: self.commitData.emit(comboBox))
        return comboBox

class Window(QWidget):
    singleton: 'Window' = None

    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle("Software tool")
        self.setGeometry(50, 50, 1800, 900)
        self.mainLayout=QHBoxLayout()
        self.setLayout(self.mainLayout)
        self.UI()
        self.table.itemChanged.connect(self._print)

    def UI(self):
        self.sublayouts = {}
        self.buttons = {}
        self._view()
        self._fillTableWidget()
        self.show()

    def _view(self):
        self.table = QTableWidget(0, 2)
        self.table.setHorizontalHeaderLabels(['Parameter', 'Data'])
        self.table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.table.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
        self.table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.table.setEditTriggers(QTableWidget.NoEditTriggers)

        self.sublayouts['table'] = QGridLayout()
        self.sublayouts['table'].addWidget(self.table, 1, 0, 4, 4)
        self.sublayouts['table'].setRowStretch(4, 1)

        self.mainLayout.addLayout(self.sublayouts['table'])

        self.table.setItemDelegateForColumn(1, DataDelegate(self.table))

    def _fillTableWidget(self):
        listCol = {
            'Parameters': ['a', 'b', 'c', 'd', 'e'],
            'Data': ['data1', 'data2', 'data3', 'data4', 'data5']}
        self.df = pd.DataFrame(listCol)
        listData = self.df['Data'].to_list()
        print(listData)
        for parameter in self.df['Parameters']:
            rowPosition = self.table.rowCount()
            self.table.insertRow(rowPosition)
            self.table.setItem(rowPosition, 0, QTableWidgetItem(parameter))
            dataItem = QTableWidgetItem()
            self.table.setItem(rowPosition, 1, dataItem)
            self.table.openPersistentEditor(self.table.item(rowPosition, 1))

    def _tableCell(self, text):
        item = QTableWidgetItem()
        item.setText(text)
        return item

    def _print(self):
        print('Item changed:')

def main():
    App=QApplication(sys.argv)
    window =Window()
    sys.exit(App.exec_())

if __name__ == '__main__':
    main()

一个可能的解决方案是将默认列表设置为委托的 instance 属性,在 createEditor() 中使用该列表并在检索模型时覆盖它:

class DataDelegate(QStyledItemDelegate):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.items = []

    def setItems(self, items):
        self.items[:] = items

    def createEditor(self, parent, opt, index):
        comboBox = QComboBox(parent)
        comboBox.addItems(self.items)
        comboBox.setCurrentIndex(1)
        comboBox.currentTextChanged.connect(
            lambda: self.commitData.emit(comboBox))
        return comboBox

class Window(QWidget):
    # ...

    def _view(self):
        # ...
        self.dataDelegate = DataDelegate(self.table)
        self.table.setItemDelegateForColumn(1, self.dataDelegate)

    def _fillTableWidget(self):
        listCol = {
            'Parameters': ['a', 'b', 'c', 'd', 'e'],
            'Data': ['data1', 'data2', 'data3', 'data4', 'data5']}
        self.df = pd.DataFrame(listCol)
        listData = self.df['Data'].to_list()
        self.dataDelegate.setItems(listData)
        # ...

注意:currentTextChanged 信号应该在您 实际上 需要它时使用(这通常是可编辑组合框所必需的,并且在某些情况下可能不会触发) ;虽然即使在不同的项目中存在相同的文本时,通常也会为不可编辑的组合框发出该信号,但这种行为 可能 在未来发生变化,并且 currentIndexChanged 通常是首选,尤其是对于模型编辑器,因为数据应该只在编辑器实际提交时更新。