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 O
,NO1
取决于FO
,NO2
取决于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 |
FO
、SO
、TO
应该遍历每个玩家的等级并带来列 header.
并且修改可以是 Selected O
、FO
或 SO
的更改值,如下所示:
| 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
),如果值要更改,请查找在列列表中,根据值获取其索引,然后根据编辑单元格的行和正在查找的列将下一列定义为该特定属性的值。
我想根据另一个单元格中的值更改一个单元格。我正在使用由 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 O
,NO1
取决于FO
,NO2
取决于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 |
FO
、SO
、TO
应该遍历每个玩家的等级并带来列 header.
并且修改可以是 Selected O
、FO
或 SO
的更改值,如下所示:
| 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
),如果值要更改,请查找在列列表中,根据值获取其索引,然后根据编辑单元格的行和正在查找的列将下一列定义为该特定属性的值。