使用spinbox小部件(PyQt5)从QTableWidget中移动项和读取值



我有一个软件工具,它有一个包含两列的表:参数和精度。"精度"中的一些参数列有spinbox小部件和一些参数只是文本"N/A"。我有两个问题:

  1. 如何上下移动表中的行,包括spinbox小部件。目前,我只能移动参数名,当我尝试向上或向下移动行时,旋转框就会消失。下面的代码函数定义了所选行向上或向下移动:"

    def _buttonMoveUpClicked(self):
    rowIndex = self.table.currentRow()
    self.table.insertRow(rowIndex - 1)
    for i in range(self.table.columnCount()):
    self.table.setItem(rowIndex - 1, i, self.table.takeItem(rowIndex + 1, i))
    self.table.selectRow(rowIndex - 1)
    self.table.removeRow(rowIndex + 1)
    def _buttonMoveDownClicked(self):
    rowIndex = self.table.currentRow()
    self.table.insertRow(rowIndex + 2)
    for i in range(self.table.columnCount()):
    self.table.setItem(rowIndex + 2, i,
    self.table.takeItem(rowIndex, i))
    self.table.selectRow(rowIndex + 2)
    self.table.removeRow(rowIndex)
    

"

  1. 我需要保存从表到列表的值。如何读取值从单元格与spinbox小部件?我现在保存它的方式:

"

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

"这是软件工具的完整代码:

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.selectionModel().selectionChanged.connect(self._updateButtonStatus)
self.buttons['Up'].clicked.connect(self._buttonMoveUpClicked)
self.buttons['Down'].clicked.connect(self._buttonMoveDownClicked)
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.buttons['Up'] = QPushButton('&Up')
self.buttons['Down'] = QPushButton('&Down')
self.sublayouts['table'] = QGridLayout()
self.sublayouts['table'].addWidget(self.table, 1, 0, 4, 4)
self.sublayouts['table'].setRowStretch(4, 1)
self.sublayouts['table'].addWidget(self.buttons['Up'], 1, 4, 1, 1, alignment=QtCore.Qt.AlignTop)
self.sublayouts['table'].addWidget(self.buttons['Down'], 2, 4, 1, 1, alignment=QtCore.Qt.AlignTop)
self.mainLayout.addLayout(self.sublayouts['table'])
def _fillListWidget(self):
list = {
'Parameters': ['a', 'b', 'c', 'd', 'e'],
'Precision': [-1, -1, 2, 3, 1]}
self.df = pd.DataFrame(list)
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 _updateButtonStatus(self):
self.buttons['Up'].setDisabled(not bool(self.table.selectedItems()) or self.table.rowCount() == 0 or self.table.currentRow()==0)
self.buttons['Down'].setDisabled(not bool(self.table.selectedItems()) or self.table.rowCount() == 0 or self.table.currentRow()==self.table.rowCount()-1)
# self._readTable()
def _buttonMoveUpClicked(self):
rowIndex = self.table.currentRow()
self.table.insertRow(rowIndex - 1)
for i in range(self.table.columnCount()):
self.table.setItem(rowIndex - 1, i, self.table.takeItem(rowIndex + 1, i))
self.table.selectRow(rowIndex - 1)
self.table.removeRow(rowIndex + 1)
def _buttonMoveDownClicked(self):
rowIndex = self.table.currentRow()
self.table.insertRow(rowIndex + 2)
for i in range(self.table.columnCount()):
self.table.setItem(rowIndex + 2, i,
self.table.takeItem(rowIndex, i))
self.table.selectRow(rowIndex + 2)
self.table.removeRow(rowIndex)
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 main():
App=QApplication(sys.argv)
window =Window()
sys.exit(App.exec_())
if __name__ == '__main__':
main()

QTableWidget不能直接这样做,因为它是一个更高级的小部件,在它的模型中不实现索引移动。

一个合适的解决方案是创建一个QAbstractTableItem子类,它也将实现moveRows()

有一个更简单的替代方案,但是请记住,模型视图应该始终跟踪索引,而删除/添加行不允许这样做。如果你想做一个好的实现,项目模型子类是必须的。

另一种选择来自这样一个事实:每当删除行(或列)时,它们的编辑器也会被销毁,并且您可以做的事情很少。
假设您总是只希望移动一行,解决方案是获取当前编辑器(及其值),删除该行,插入新行,并使用先前读取的值为其创建一个新的编辑器。

为了简单起见(并遵循OOP模式),我创建了一个接受当前行和"delta"参数,告诉它行是否必须"移动"。向上或向下

def _moveRow(self, row, delta):
colIndex = self.table.currentColumn()
items = [self.table.takeItem(row, c) for c in range(self.table.columnCount())]
oldSpinBox = self.table.cellWidget(row, 1)
self.table.removeRow(row)
newRow = row + delta
self.table.insertRow(newRow)
for i, item in enumerate(items):
self.table.setItem(newRow, i, item)
if isinstance(oldSpinBox, QAbstractSpinBox):
newSpinBox = QSpinBox()
newSpinBox.setValue(oldSpinBox.value())
self.table.setCellWidget(newRow, 1, newSpinBox)
if colIndex >= 0:
self.table.setCurrentCell(newRow, colIndex)
def _buttonMoveUpClicked(self):
rowIndex = self.table.currentRow()
if rowIndex > 0:
self._moveRow(rowIndex, -1)
def _buttonMoveDownClicked(self):
rowIndex = self.table.currentRow()
if rowIndex < self.table.rowCount() - 1:
self._moveRow(rowIndex, 1)
如前所述,这是一个非常简单的解决方案,并且只适用于硬编码的行/列小部件。一个更正确和有意识的解决方案是创建QAbstractTableModel的子类并实现moveRows()函数:这样做允许更适当的实现,将提供正确的编辑器(因此不需要setCellWidget()),并将允许更正确的行移动。

相关内容

最新更新