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

Posted

技术标签:

【中文标题】PyQt5 - 在表格小部件的列中创建一个检查项,即使行数与旋转框不同【英文标题】:PyQt5 - Create a check item in a column of a table widget even with the number of rows varying from a spinbox 【发布时间】:2020-07-19 21:20:51 【问题描述】:

我是 PyQt5 的新手,我正在使用 Qtdesigner 开发一个界面。

我正在从微调框中控制表格小部件的行数。但是,在更改行数时,我需要保留 a 列的检查选项。

我设法根据旋转框中的 valueChanged 更改了行数,但是我创建的用于创建检查的循环不管行数都不起作用。

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(519, 468)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.spinBox = QtWidgets.QSpinBox(self.centralwidget)
        self.spinBox.setGeometry(QtCore.QRect(80, 131, 41, 31))
        self.spinBox.setProperty("value", 2)
        self.spinBox.setObjectName("spinBox")
        self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
        self.tableWidget.setGeometry(QtCore.QRect(160, 80, 341, 101))
        self.tableWidget.setObjectName("tableWidget")
        self.tableWidget.setColumnCount(2)
        self.tableWidget.setRowCount(2)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setVerticalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setHorizontalHeaderItem(1, item)
        item = QtWidgets.QTableWidgetItem()
        item.setFlags(QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled)
        item.setCheckState(QtCore.Qt.Checked)
        self.tableWidget.setItem(0, 0, item)
        item = QtWidgets.QTableWidgetItem()
        item.setFlags(QtCore.Qt.ItemIsEnabled)
        item.setCheckState(QtCore.Qt.Checked)
        self.tableWidget.setItem(1, 0, item)
        item = QtWidgets.QTableWidgetItem()
        self.tableWidget.setItem(1, 1, item)
        self.tableWidget.verticalHeader().setVisible(False)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 519, 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)
        self.spinBox.valueChanged['int'].connect(self.tableWidget.setRowCount)

        for i in range(self.tableWidget.rowCount()):
            item = QtWidgets.QTableWidgetItem()
            item.setFlags(QtCore.Qt.ItemIsEnabled)
            item.setCheckState(QtCore.Qt.Checked)
            self.tableWidget.setItem(i, 0, item)

        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", "d"))
        item = self.tableWidget.verticalHeaderItem(1)
        item.setText(_translate("MainWindow", "e"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "a"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "c"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        self.tableWidget.setSortingEnabled(__sortingEnabled)


    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        item = self.tableWidget.verticalHeaderItem(0)
        item.setText(_translate("MainWindow", "d"))
        item = self.tableWidget.verticalHeaderItem(1)
        item.setText(_translate("MainWindow", "e"))
        item = self.tableWidget.horizontalHeaderItem(0)
        item.setText(_translate("MainWindow", "a"))
        item = self.tableWidget.horizontalHeaderItem(1)
        item.setText(_translate("MainWindow", "c"))
        __sortingEnabled = self.tableWidget.isSortingEnabled()
        self.tableWidget.setSortingEnabled(False)
        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_())

【问题讨论】:

我可以看到图片中的复选框。你能准确解释什么没有按预期工作吗? 你的意思是当你添加一个新行时它没有得到一个复选框? 【参考方案1】:

首先,您似乎正在编辑pyuic 生成文件的输出,或者您正在尝试模仿它的行为。无论如何,这是永远不应该做的事情。

这些文件应该保持原样,您应该只将它们用作模块;要了解如何正确执行此操作,请阅读有关 using Designer 的更多信息。如果您试图模仿他们的行为,那么您不应该这样做:处理 pyuic 文件的方式仅被视为“解释层”,以便创建 GUI 对象并使其可以从 python 访问。如果您是从代码构建 GUI,只需将要使用的 QWidget 子类化(通常是 QWidget、QDialog 或 QMainWindow)。

现在,问题是每当setRowCount() 被调用...:

[it] 将此表模型中的行数设置为行。如果这小于 rowCount(),则不需要的行中的数据被丢弃

这显然意味着,如果您要删除行,则会丢失该行中的所有项目(包括它们完全可以检查的事实)。

要正确更新内容并添加可检查的项目,您需要在动态删除或添加项目的特定方法中执行此操作。

在下一个示例中,我将展示如何正确实现这一点(并且以更简单、更清晰的方式):

from PyQt5 import QtCore, QtWidgets

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        central = QtWidgets.QWidget()
        self.setCentralWidget(central)
        layout = QtWidgets.QHBoxLayout(central)
        self.spin = QtWidgets.QSpinBox()
        layout.addWidget(self.spin)
        self.table = QtWidgets.QTableWidget(2, 2)
        layout.addWidget(self.table)
        self.table.verticalHeader().setVisible(False)
        for col, label in enumerate(('a', 'c')):
            header = QtWidgets.QTableWidgetItem(label)
            self.table.setHorizontalHeaderItem(col, header)
            if col:
                continue
            for row in range(self.table.rowCount()):
                item = QtWidgets.QTableWidgetItem()
                item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                item.setCheckState(QtCore.Qt.Checked)
                self.table.setItem(row, col, item)

        self.spin.setValue(self.table.rowCount())
        self.spin.valueChanged.connect(self.setRowCount)

    def setRowCount(self, count):
        if count == self.table.rowCount():
            return
        # if there are too many rows, remove them
        while self.table.rowCount() > count:
            self.table.removeRow(self.table.rowCount() - 1)
        # if rows are going to be added, create checkable items for them
        while self.table.rowCount() < count:
            row = self.table.rowCount()
            self.table.insertRow(row)
            item = QtWidgets.QTableWidgetItem()
            item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
            item.setCheckState(QtCore.Qt.Checked)
            self.table.setItem(row, 0, item)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    test = MainWindow()
    test.show()
    sys.exit(app.exec_())

作为旁注,有几个注意事项:

布局管理器应始终用于小部件,否则内容可能会变得不可见或无法调整其位置; 您定义了retranslateUi 两次;我想这是编辑 pyuic 文件后留下的东西,但无论如何,重新定义具有相同名称的函数会导致覆盖它(除非它们每个都有唯一的装饰器)

【讨论】:

以上是关于PyQt5 - 在表格小部件的列中创建一个检查项,即使行数与旋转框不同的主要内容,如果未能解决你的问题,请参考以下文章

在 pyqt5 小部件中更新 matplotlib

PyQt5.如何根据几个参数填充表格小部件?

如何在 PyQt5 Python 中更改表格小部件中滚动条的颜色

PyQt5 QWidget不填充父

如何在 PyQt5 中为 QGridLayout 添加拉伸?

如何在颤动的另一个有状态小部件中访问在一个有状态小部件中创建的对象