使用Spinbox小部件(PYQT5)从QtableWidget移动项目并读取值

发布于 2025-01-27 16:10:52 字数 5825 浏览 2 评论 0原文

我有一个软件工具,该工具的表装有两个列:参数和精度。 “ Precision”列中的某些参数具有SpinBox小部件,而某些参数仅具有文本“ N/A”。 我有两个问题

  1. 。目前,当我尝试向上或向下移动行时,我只能移动参数名称,并且Spinbox消失。 以下是具有函数的代码,以定义所选行向上或向下移动: '''

      def _buttonmoveupclicked(self):
         rowindex = self.table.currentrow()
         self.table.inserstrow(Rowindex -1)
         对于我的范围(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.inserstrow(rowindex + 2)
         对于我的范围(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()

I have a software tool that has a table filled with two columns: parameter and precision. Some parameters in the "Precision" column have spinbox widget and some parameters have just text "N/A".
I have two questions:

  1. How to move the rows in a table up and down including the spinbox widget. Currently I was able to move only the parameter name and the spinbox disappears as soon as I try to move row up or down.
    Below is the code with functions defining the move of selected row up or down:
    '''

     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. I need to save the values from table to the lists. How to read the values from the cells with spinbox widget?
    The way how I'm trying to save it now:

'''

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

'''
This is the full code for the software tool:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

萌酱 2025-02-03 16:10:52

您无法使用QTableWidget直接执行此操作,因为它是一个不实现其模型中索引运动的较高级别的小部件。

a 适当的解决方案将是创建一个QabstracttabletableItem子类,该子类也将实现 MOVOWS()

可以使用更简单的替代方案,但是请记住,模型视图应始终跟踪索引,并且删除/添加行不允许。如果您想执行良好的实现,则必须进行项目模型子类。

替代方案来自以下事实:每当删除行(或列)时,他们的编辑者也会被销毁,您几乎无法使用它。

假设您始终想要仅移动仅一行,则解决方案是获取当前的编辑器(及其值),删除行,插入新的编辑器,然后创建新的编辑器具有先前读取值的新编辑器。

出于简单原因(并遵循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的子类并实现MOVOVOWS()函数:这样做允许更正确的实现,将提供正确的编辑器(因此,否setCellWidget( )是必需的),并且将允许更多正确的行运动。

You cannot directly do that with QTableWidget, as it is an higher level widget that doesn't implement index movements in its model.

A proper solution would be to create a QAbstractTableItem subclass that would also implement moveRows().

A simpler alternative is available, but remember that model views should always keep track of indexes, and deleting/adding rows won't allow it. If you want to do a good implementation, an item model subclass is mandatory.

The alternative comes from the fact that whenever rows (or columns) are removed, their editors are destroyed too, and there's very little you can do with it.
Assuming that you always want to move only one row, the solution is to get the current editor (and its value), delete the row, insert the new one, and create a new editor for it with the previously read value.

For simplicity reasons (and following OOP patterns), I created a common function that accepts the current row and a "delta" argument that tells it if the row has to be "moved" up or down.

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)

As said, this is a very simplistic solution, and only works for hardcoded row/column widgets. A more correct and aware solution is to create a subclass of QAbstractTableModel and implement the moveRows() function: doing this allows a more proper implementation, will provide the correct editors (so that no setCellWidget() would be required) and will allow more correct row movements.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文