QTableView 基于另一个单元格动态更新 Python

QTableView update dynamic based on another cell Python

我想根据另一个单元格中的值更改一个单元格。我正在使用由 QAbstractTableModel 和 pandas 数据框填充的 QTableView。 这是Pandas型号的代码:

class PandasModelEditable(QAbstractTableModel):
    def __init__(self, data, parent=None):
        QAbstractItemModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=Qt.DisplayRole):
        if index.isValid():
            if role == Qt.DisplayRole or role == Qt.EditRole:
                return unicode(self._data.iloc[index.row(), index.column()])
        return None

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole:
            return None
        if orientation == Qt.Horizontal:
            try:
                return '%s' % unicode(self._data.columns.tolist()[section])
            except (IndexError,):
                return unicode()
        elif orientation == Qt.Vertical:
            try:
                return '%s' % unicode(self._data.index.tolist()[section])
            except (IndexError,):
                return unicode()

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable

    def setData(self, index, value, role=Qt.EditRole):
        if index.isValid():
            self._data.iloc[index.row(), index.column()] = value
            if self.data(index, Qt.DisplayRole) == value:
                self.dataChanged.emit(index, index)
                return True
        return False

主要数据框(代码中的df)具有以下结构:

| Player  | O1_Score | O2_Score | O3_Score | O1_Rank | O2_Rank | O3_Rank |
| ------- | -------- | -------- | -------- | ------- | ------- | ------- |
| First   | 9.66     | 10.24    | 8.52     |   2     |   1     |   3     |
| Second  | 7.45     | 11.31    | 12.56    |   3     |   2     |   1     |

显然我的数据框有更多的分数 (83) 及其各自的排名,仅举个例子

table(代码中的 dataframe_tp)和 table 的数据框具有完全相同的列,如下所示,在 GUI 中具有以下视觉效果:

| Player  | Selected O | Score | FO | NO1 | SO | NO2 | TO | NO3 |
| ------- | ---------- | ----- | -- | --- | -- | --- | -- | --- |
| First   | ---------- | ----- | 1  | --- | 2  | --- | 3  | --- |
| Second  | ---------- | ----- | 1  | --- | 2  | --- | 3  | --- |

其中:Selected O表示选择的选项,FO表示第一个选项,SO表示第二个选项,TO表示第三个选项,NO表示名称带有数字的选项以标识以上选项

基于上面的table,Score取决于Selected ONO1取决于FONO2取决于SO, NO3 取决于 TO.

代码:

self.squad_table = QTableView()

self.dataframe_tp = df.loc[:, ['Player']]
self.dataframe_tp["Selected O"] = '-'
self.dataframe_tp["Score"] = 0
self.dataframe_tp['FO'] = 1
self.dataframe_tp['NO1'] = '-'
self.dataframe_tp['SO'] = 2
self.dataframe_tp['NO2'] = '-'
self.dataframe_tp['TO'] = 3
self.dataframe_tp['NO3'] = '-'

model = PandasModelEditable(self.dataframe_tp)
self.squad_table.setModel(model)
self.squad_table.show()

预期输出为:

| Player  | Selected O | Score | FO |   NO1   | SO |    NO2   | TO |    NO3   |
| ------- | ---------- | ----- | -- | ------- | -- | -------- | -- | -------- |
| First   | O3_Score   | 8.52  | 1  | O2_Rank | 2  | O1_Rank  | 3  | O3_Rank  |
| Second  | O2_Score   | 11.31 | 1  | O3_Rank | 2  | O2_Rank  | 3  | O1_Rank  |

FOSOTO 应该遍历每个玩家的等级并带来列 header.

并且修改可以是 Selected OFOSO 的更改值,如下所示:

| Player  | Selected O | Score | FO |   NO1   | SO |    NO2   | TO |    NO3   |
| ------- | ---------- | ----- | -- | ------- | -- | -------- | -- | -------- |
| First   | O1_Score   | 9.66  | 2  | O1_Rank | 2  | O1_Rank  | 3  | O3_Rank  |
| Second  | O2_Score   | 11.31 | 1  | O3_Rank | 1  | O3_Rank  | 3  | O1_Rank  |

对于第一次使用,只编辑 classes,因为@musicamante 告诉我实现这个代码:

class CustomizedPandasModel(QAbstractTableModel):

    # Previous code hidden to clarify changes, above code is exactly the same

    def setData(self, index, value, role=Qt.EditRole):
        based_columns = [6, 8, 10, 12]
        if role == Qt.EditRole:
            row = index.row()
            column = index.column()
            tmp = str(value)
            
            if column in based_columns:

                # If selected column in list of accepted columns to edit

                if column == 6 and tmp in self._data.columns.values.tolist():

                    # If value is in the list of headers

                    index_no = self._data.columns.get_loc(tmp) # Get index of column
                    self._data.iloc[row, column + 1] = self._data.iloc[row, index_no] # Set adjacent column as the value of that attribute
                    self._data.iloc[row, column] = tmp # Set actual cell to new value
                self.dataChanged.emit(index, index)

基本上唯一的变化是在 class 模型 def setdata 中,我为我的实用程序添加了一个索引值列列表 (based_columns),如果值要更改,请查找在列列表中,根据值获取其索引,然后根据编辑单元格的行和正在查找的列将下一列定义为该特定属性的值。