从 PyQt 中的表格小部件中选择多行后,单元格小部件(按钮)显示在错误的位置

Posted

技术标签:

【中文标题】从 PyQt 中的表格小部件中选择多行后,单元格小部件(按钮)显示在错误的位置【英文标题】:After selecting multiple rows from a table widget in PyQt, the cell widget(button) is shown in a wrong position 【发布时间】:2020-09-04 13:56:54 【问题描述】:

我想创建一个表格小部件,每行有两个按钮,并在插入行后选择一些行。

以编程方式选择行后,我发现表格中的按钮被移动到错误的位置。如果我只选择一行,一切都很好。

根据@eyllanesc 的建议,我尝试重现该问题,但从下面的代码中看起来不错。我的代码是在 QGIS 而不是纯 PyQt5 上运行的,所以我无法真正重现它。

我不知道为什么会出现这个问题以及如何解决这个问题。 有没有办法重置单元格小部件的位置?或者我可以手动设置单元格小部件的位置。如果可能的话,也许我可以找到一种方法来设置它。谢谢。

我的代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(400, 200)
        self.gridLayout = QtWidgets.QGridLayout(Dialog)
        self.gridLayout.setObjectName("gridLayout")

        # add a button on the window
        self.pushButton = QtWidgets.QPushButton(Dialog)
        self.pushButton.setText("add rows")
        self.gridLayout.addWidget(self.pushButton, 1, 6, 1, 1)

        self.tableWidget = QtWidgets.QTableWidget(Dialog)
        self.tableWidget.setMinimumSize(QtCore.QSize(0, 0))
        self.tableWidget.setAlternatingRowColors(True)
        self.tableWidget.setColumnCount(0)
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setRowCount(0)
        self.tableWidget.horizontalHeader().setVisible(True)
        self.tableWidget.horizontalHeader().setDefaultSectionSize(150)
        self.tableWidget.horizontalHeader().setMinimumSectionSize(39)
        self.tableWidget.horizontalHeader().setStretchLastSection(True)
        self.tableWidget.verticalHeader().setDefaultSectionSize(45)
        self.tableWidget.verticalHeader().setMinimumSectionSize(35)
        self.tableWidget.setMinimumSize(450,260)
        # set column count
        self.tableWidget.setColumnCount(3)
        # add two rows
        ui.tableWidget.setRowCount(2)
        for i in range(2):
            # button 1 of column1
            pushButton1 = QtWidgets.QPushButton(ui.tableWidget)
            pushButton1.setText('a' + str(i))
            ui.tableWidget.setCellWidget(i, 0, pushButton1)

            # button 2 of column2
            pushButton2 = QtWidgets.QPushButton(ui.tableWidget)
            pushButton2.setText('b' + str(i))
            ui.tableWidget.setCellWidget(i, 1, pushButton2)

            # an item of column3
            qItem = QtWidgets.QTableWidgetItem(str(i))
            ui.tableWidget.setItem(i, 2, qItem)
            qItem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)

        self.gridLayout.addWidget(self.tableWidget, 0, 0, 1, 7)


        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", ""))
        self.tableWidget.setSortingEnabled(True)

    def addRows(self):
        # change to mutiple selection mode
        self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection)
        
        # insert three new rows and select them
        for i in range(3):
            row = self.insertRow()
            # select the row
            self.tableWidget.selectRow(row)
        
        # change select mode back
        self.tableWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
    
    def insertRow(self):
         # insert a row to the table
        rowCount = self.tableWidget.rowCount()
        self.tableWidget.insertRow(rowCount)
        
        # row to insert 
        row = self.tableWidget.rowCount() - 1

        # button 1 of column1
        pushButton1 = QtWidgets.QPushButton(self.tableWidget)
        pushButton1.setText('a' + str(row))
        self.tableWidget.setCellWidget(row, 0, pushButton1)

        # button 2 of column2
        pushButton2 = QtWidgets.QPushButton(self.tableWidget)
        pushButton2.setText('b' + str(row))
        self.tableWidget.setCellWidget(row, 1, pushButton2)

        # an item of column3
        qItem = QtWidgets.QTableWidgetItem(str(row))
        self.tableWidget.setItem(row, 2, qItem)
        qItem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsEditable)
    
        return row


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = QtWidgets.QDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    ui.pushButton.clicked.connect(ui.addRows)
    Dialog.show()
    sys.exit(app.exec_())

表格截图如下:

【问题讨论】:

请提供minimal reproducible example 【参考方案1】:

我未能在 QGIS 之外重现该问题。但是在玩弄之后,我找到了解决问题的方法。

所以在插入一些记录后,我在按钮列上的表格中调用 sortItems(),然后所有按钮将显示在正确的位置。不知道为什么,但它对我有用。

tableWidget.sortItems(0)

【讨论】:

【参考方案2】:

只需添加按钮并连接您的代码。您需要启用排序。我也不确定你为什么要使用扩展选择。我希望下面的代码可以解决您的问题。

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(1020, 950)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(9, 9, 581, 211))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(3)
        self.tableWidget.setRowCount(5)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(3, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(4, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(0, 1, item)
        item = QtWidgets.QTableWidgetItem()

        item = QtWidgets.QPushButton("its a button")
        
        self.tableWidget.setCellWidget(0, 2, item)
        
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(2, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(3, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(3, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(3, 2, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(4, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(4, 1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(4, 2, item)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 1020, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        item = self.tableWidget.verticalHeaderItem(0)
        item.setText(_translate("MainWindow", "Row1"))
        item = self.tableWidget.verticalHeaderItem(1)
        item.setText(_translate("MainWindow", "Row2"))
        item = self.tableWidget.verticalHeaderItem(2)
        item.setText(_translate("MainWindow", "Row3"))
        item = self.tableWidget.verticalHeaderItem(3)
        item.setText(_translate("MainWindow", "Row4"))
        item = self.tableWidget.verticalHeaderItem(4)
        item.setText(_translate("MainWindow", "Row5"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "Col1"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "Col2"))
        item = self.tableWidget.horizontalHeaderItem(2)
        item.setText(_translate("MainWindow", "Col3"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        item = self.tableWidget.item(0, 0)
        item.setText(_translate("MainWindow", "1"))
        item = self.tableWidget.item(0, 1)
        
        item.setText(_translate("MainWindow", "1"))
        item = self.tableWidget.item(1, 0)
        item.setText(_translate("MainWindow", "2"))
        item = self.tableWidget.item(1, 1)
        item.setText(_translate("MainWindow", "2"))
        item = self.tableWidget.item(1, 2)
        item.setText(_translate("MainWindow", "2"))
        item = self.tableWidget.item(2, 0)
        item.setText(_translate("MainWindow", "3"))
        item = self.tableWidget.item(2, 1)
        item.setText(_translate("MainWindow", "3"))
        item = self.tableWidget.item(2, 2)
        item.setText(_translate("MainWindow", "3"))
        item = self.tableWidget.item(3, 0)
        item.setText(_translate("MainWindow", "4"))
        item = self.tableWidget.item(3, 1)
        item.setText(_translate("MainWindow", "4"))
        item = self.tableWidget.item(3, 2)
        item.setText(_translate("MainWindow", "4"))
        item = self.tableWidget.item(4, 0)
        item.setText(_translate("MainWindow", "5"))
        item = self.tableWidget.item(4, 1)
        item.setText(_translate("MainWindow", "5"))
        item = self.tableWidget.item(4, 2)
        item.setText(_translate("MainWindow", "5"))
        self.tableWidget.setSortingEnabled(__sortingEnabled)



if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

【讨论】:

谢谢@Elan,但我认为这个问题与排序无关。我在原始代码中设置了 setSortingEnabled()。

以上是关于从 PyQt 中的表格小部件中选择多行后,单元格小部件(按钮)显示在错误的位置的主要内容,如果未能解决你的问题,请参考以下文章

在 QTableWidget 的中心对齐单元格小部件?

PyQt5 - 在表格小部件的列中创建一个检查项,即使行数与旋转框不同

如何使 QTableWidget 内的单元格小部件的背景不可选?

QTablewidget 在 PyQt5 中不显示新的 cellWidgets

从表格小部件中的选定单元格中检索单元格数据

PyQt4:使用 QPushButton 小部件从 QList 小部件中删除项目