如果更改单元格值则调用一个函数 - 对于 table 中旋转框的动态数量

Call a function if cell value is changed - for dynamic number of spinBoxes in a table

我正在编写一个软件工具,其中 table 填充了两列:参数和精度。 “Precision”列中的一些参数具有 spinBox 小部件,而一些参数只有文本“N/A”。旋转框的数量是动态的。如果带有旋转框的单元格的值发生变化,如何调用函数?

我尝试用 self.table.currentItemChanged.connect(self._print) 来做,但它并没有完全满足我的需要 - 它仅在我更改 spinBox 值并在更改行选择之后调用函数,而我需要调用函数每次 spinBox 值改变时。

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

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()

    def UI(self):
        self.sublayouts = {}
        self.buttons = {}
        self._view()
        self._fillListWidget()
        self.table.currentItemChanged.connect(self._print)
        self.show()

    def _view(self):
        self.table = QTableWidget(0, 2)
        self.table.setHorizontalHeaderLabels(['Parameter', 'Precision'])
        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'])

    def _fillListWidget(self):
        listCol = {
            'Parameters': ['a', 'b', 'c', 'd', 'e'],
            'Precision': [-1, -1, 2, 3, 1]}
        self.df = pd.DataFrame(listCol)
        for row in zip(*self.df.to_dict('list').values()):
            itemColumn = QTableWidgetItem(
                row[self.df.columns.get_loc("Parameters")])
            rowPosition = self.table.rowCount()
            self.table.insertRow(rowPosition)
            itemTable = self._tableCell(row[self.df.columns.get_loc("Parameters")])
            self.table.setItem(rowPosition, 0, itemTable)
            df_tmp = self.df[self.df['Parameters'] == row[self.df.columns.get_loc("Parameters")]]
            if df_tmp['Precision'].values[0] >= 0:
                self.spinBox=QSpinBox()
                self.spinBox.setValue(df_tmp['Precision'].values[0])
                self.table.setCellWidget(rowPosition, 1, self.spinBox)
            else:
                itemTable = self._tableCell('N/A')
                self.table.setItem(rowPosition, 1, itemTable)

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

    def _readTable(self):
        list_Parameters = []
        list_Precision = []
        print('1')
        for i in range(self.table.rowCount()):
            print(self.table.item(i, 0).text())
            list_Parameters.append(self.table.item(i, 0).text())
            list_Precision.append(self.table.item(i, 1).text())

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

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

if __name__ == '__main__':
    main()

您不应设置小部件项目,而应使用 Qt.DisplayRole 设置索引值并打开 持久性编辑器,默认情况下它已经是一个旋转框对于数值。

由于您需要专门的行为,您可以使用自定义委托来实现该委托,方法是返回一个带有 createEditor(), and also connects the spin box valueChanged signal to the delegate's commitData() 的自定义 QSpinBox,它实际上会在模型上设置数据。

通过这种方式,您不仅可以连接到 table 的 itemChanged 以接收有关数据更改的通知,而且您还可以 直接 访问 table 数据(这在您的情况下不起作用,因为数据未设置并且仅在旋转框中可用)。

class PrecisionDelegate(QStyledItemDelegate):
    def createEditor(self, parent, opt, index):
        editor = QSpinBox(parent)
        editor.setMinimum(-1)
        editor.setSpecialValueText('N/A')
        editor.valueChanged.connect(lambda: self.commitData.emit(editor))
        return editor


class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle("Software tool")
        self.mainLayout = QHBoxLayout(self)
        self.UI()
        self.table.itemChanged.connect(self._print)

    def _view(self):
        # ...
        self.table.setItemDelegateForColumn(1, PrecisionDelegate(self.table))

    def _fillListWidget(self):
        listCol = {
            'Parameters': ['a', 'b', 'c', 'd', 'e'],
            'Precision': [-1, -1, 2, 3, 1]}
        self.df = pd.DataFrame(listCol)
        for parameter, precision in zip(self.df['Parameters'], self.df['Precision']):
            rowPosition = self.table.rowCount()
            self.table.insertRow(rowPosition)
            self.table.setItem(rowPosition, 0, QTableWidgetItem(parameter))
            precisionItem = QTableWidgetItem()
            precisionItem.setData(QtCore.Qt.DisplayRole, precision)
            self.table.setItem(rowPosition, 1, precisionItem)
            self.table.openPersistentEditor(self.table.item(rowPosition, 1))