我应该如何在 PyQt5 的 Table Widgets 中连接 CheckBox 单击信号? [英] How should I connect CheckBox clicked signals in Table Widgets in PyQt5?

查看:190
本文介绍了我应该如何在 PyQt5 的 Table Widgets 中连接 CheckBox 单击信号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想向表格小部件中的各种单元格添加各种小部件,并且我想在这些小部件的值发生更改时触发命令.我可以根据需要将小部件放入表格中,但我在连接信号时遇到问题,因此我无法知道哪个小部件生成了信号.

下面是一个简单的例子来解释这个问题,只使用复选框:

from PyQt5 import QtWidgets, QtGui, QtCore类 Main(QtWidgets.QMainWindow):def __init__(self, parent=None):super().__init__(parent)# 创建表:self.table = QtWidgets.QTableWidget()[self.table.insertRow(i) for i in [0,1,2]][self.table.insertColumn(i) for i in [0,1]]# 设置第一列的值:self.table.setItem(0, 0, QtWidgets.QTableWidgetItem('A'))self.table.setItem(1, 0, QtWidgets.QTableWidgetItem('B'))self.table.setItem(2, 0, QtWidgets.QTableWidgetItem('C'))# 将复选框添加到第二列:cb0 = QtWidgets.QCheckBox( parent=self.table )cb1 = QtWidgets.QCheckBox( parent=self.table )cb2 = QtWidgets.QCheckBox( parent=self.table )self.table.setCellWidget(0, 1, cb0)self.table.setCellWidget(1, 1, cb1)self.table.setCellWidget(2, 1, cb2)# 连接表信号:self.table.cellChanged.connect(self.cell_changed)self.table.itemChanged.connect(self.item_changed)# 连接复选框信号:cb0.clicked.connect(self.checkbox_clicked)cb1.clicked.connect(self.checkbox_clicked)cb2.clicked.connect(self.checkbox_clicked)# 表演:self.setCentralWidget(self.table)self.setWindowTitle('TableWidget, CheckBoxes')自我展示()def cell_changed(self, row, col):打印(行,列)def checkbox_clicked(self,checked):打印(选中)def item_changed(self, item):打印(项目)如果 __name__ == '__main__':导入系统app = QtWidgets.QApplication(sys.argv)主要 = 主要()app.exec_()

基于table.cellChanged.connect,我天真地期望当复选框改变时cellChanged 信号.然而,不产生该信号.itemChanged 信号也不是.我确实可以看到 clicked 信号,但这不是很有用,因为不清楚哪个复选框产生了信号.

解决问题的一种方法是为每个复选框创建一个不同的 checkbox_clicked 函数,但这似乎不太优雅.

我的问题是:

  1. 为什么在更改复选框时既不会生成 cellChanged 信号,也不会生成 itemChanged 信号?

  2. 应该如何连接信号才能知道哪个复选框生成了 clicked 信号?

解决方案

  1. 为什么在以下情况下既不生成 cellChanged 也不生成 itemChanged 信号复选框已更改?

因为当您使用 setCellWidget() 时,不会创建 QTableWidgetItem,如果我们查看 cellChangeditemChanged:

<块引用>

void QTableWidget::cellChanged(int row, int column)

每当由行和列指定的单元格中项目的数据发生变化时,就会发出此信号.

void QTableWidget::itemChanged(QTableWidgetItem *item)

只要item 的数据发生变化,就会发出这个信号.

<小时><块引用>

  1. 应该如何连接信号才能知道哪个复选框产生了点击信号?

获取方式是间接的,首先要知道的是,通过setCellWidget()方法添加widget时,viewport()viewport()code>QTableWidget 设置为父级.

还有一点应该知道的是,通过pos()访问的widget的位置是相对于父级的,也就是说,在我们的例子中是相对于viewport().

有一个非常有用的方法叫做sender(),它返回发出信号的对象,在这种情况下它将返回QCheckBox.

因为小部件相对于 viewport() 的位置是已知的,它的 QModelIndex 可以通过 indexAt() 方法,QModelIndex 有细胞.

以上所有内容均在以下示例中实现:

from PyQt5 import QtWidgets, QtGui, QtCore类 Main(QtWidgets.QMainWindow):def __init__(self, parent=None):super().__init__(parent)# 创建表:self.table = QtWidgets.QTableWidget()self.table.setRowCount(3)self.table.setColumnCount(2)对于我,枚举中的字母(ABC"):self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))对于 i 在范围内(self.table.rowCount()):ch = QtWidgets.QCheckBox(parent=self.table)ch.clicked.connect(self.onStateChanged)self.table.setCellWidget(i, 1, ch)self.setCentralWidget(self.table)self.setWindowTitle('TableWidget, CheckBoxes')自我展示()def onStateChanged(self):ch = self.sender()打印(ch.parent())ix = self.table.indexAt(ch.pos())打印(ix.row(),ix.column(),ch.isChecked())如果 __name__ == '__main__':导入系统app = QtWidgets.QApplication(sys.argv)主要 = 主要()sys.exit(app.exec_())

<小时>

另一种方法是通过 lambda 方法或 partial.functions 直接传递新参数.

from PyQt5 import QtWidgets, QtGui, QtCore类 Main(QtWidgets.QMainWindow):def __init__(self, parent=None):super().__init__(parent)# 创建表:self.table = QtWidgets.QTableWidget()self.table.setRowCount(3)self.table.setColumnCount(2)对于我,枚举中的字母(ABC"):self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))对于 i 在范围内(self.table.rowCount()):ch = QtWidgets.QCheckBox(parent=self.table)ch.clicked.connect(lambda 被检查,row=1,col=i: self.onStateChanged(checked, row, col))self.table.setCellWidget(i, 1, ch)self.setCentralWidget(self.table)self.setWindowTitle('TableWidget, CheckBoxes')自我展示()def onStateChanged(自我,检查,行,列):打印(选中,行,列)如果 __name__ == '__main__':导入系统app = QtWidgets.QApplication(sys.argv)主要 = 主要()sys.exit(app.exec_())

如果您想了解更多有关如何通过 connect() 传递额外参数的信息,您可以查看这个答案.

I would like to add various widgets to various cells in a Table Widget, and I would like to trigger commands when those widgets' values are changed. I can get the widgets into the table as desired, but I'm having problems connecting signals so that I know which widget has generated the signal.

Below is a simple example explaining the problem, using just checkboxes:

from PyQt5 import QtWidgets, QtGui, QtCore


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # create table:
        self.table = QtWidgets.QTableWidget()
        [self.table.insertRow(i) for i in [0,1,2]]
        [self.table.insertColumn(i) for i in [0,1]]
        # set values for first column:
        self.table.setItem(0, 0, QtWidgets.QTableWidgetItem('A') )
        self.table.setItem(1, 0, QtWidgets.QTableWidgetItem('B') )
        self.table.setItem(2, 0, QtWidgets.QTableWidgetItem('C') )
        # add checkboxes to second column:
        cb0  = QtWidgets.QCheckBox( parent=self.table )
        cb1  = QtWidgets.QCheckBox( parent=self.table )
        cb2  = QtWidgets.QCheckBox( parent=self.table )
        self.table.setCellWidget(0, 1, cb0)
        self.table.setCellWidget(1, 1, cb1)
        self.table.setCellWidget(2, 1, cb2)
        # connect table signals:
        self.table.cellChanged.connect(self.cell_changed)
        self.table.itemChanged.connect(self.item_changed)
        # connect checkbox signals:
        cb0.clicked.connect(self.checkbox_clicked)
        cb1.clicked.connect(self.checkbox_clicked)
        cb2.clicked.connect(self.checkbox_clicked)
        # show:
        self.setCentralWidget(self.table)
        self.setWindowTitle('TableWidget, CheckBoxes')
        self.show()

    def cell_changed(self, row, col):
        print(row, col)
    def checkbox_clicked(self, checked):
        print(checked)
    def item_changed(self, item):
        print(item)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main = Main()
    app.exec_()

Based on table.cellChanged.connect I would naively expect a cellChanged signal when the checkboxes are changed. However this signal is not generated. Nor is the itemChanged signal. I can indeed see the clicked signals, but that is not very useful because it is unclear which checkbox has produced the signal.

One way to solve the problem is to create a different checkbox_clicked function for each checkbox, but that hardly seems elegant.

My questions are:

  1. Why is neither a cellChanged nor an itemChanged signal generated when a checkbox is changed?

  2. How should signals be connected in order to know which checkbox has generated the clicked signal?

解决方案

  1. Why is neither a cellChanged nor an itemChanged signal generated when a checkbox is changed?

because when you use setCellWidget() a QTableWidgetItem is not created, and if we check the documentation of cellChanged and itemChanged:

void QTableWidget::cellChanged(int row, int column)

This signal is emitted whenever the data of the item in the cell specified by row and column has changed.

void QTableWidget::itemChanged(QTableWidgetItem *item)

This signal is emitted whenever the data of item has changed.


  1. How should signals be connected in order to know which checkbox has generated the clicked signal?

The way to obtain is indirectly, the first thing to know is that when the widget is added through the setCellWidget() method, the viewport() of the QTableWidget is set as a parent.

Also another thing that should be known is that the position of a widget that is accessed through pos() is relative to the parent, that is, in our case relative to viewport().

There is a very useful method called sender() that returns the object that emits the signal, in this case it will return the QCheckBox.

As the position of the widget with respect to the viewport() is known, its QModelIndex is accessed through the indexAt() method, the QModelIndex has the information of the cell.

All of the above is implemented in the following example:

from PyQt5 import QtWidgets, QtGui, QtCore


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # create table:
        self.table = QtWidgets.QTableWidget()
        self.table.setRowCount(3)
        self.table.setColumnCount(2)
        for i, letter in enumerate("ABC"):
            self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))
        for i in range(self.table.rowCount()):
            ch = QtWidgets.QCheckBox(parent=self.table)
            ch.clicked.connect(self.onStateChanged)
            self.table.setCellWidget(i, 1, ch)
        self.setCentralWidget(self.table)
        self.setWindowTitle('TableWidget, CheckBoxes')
        self.show()

    def onStateChanged(self):
        ch = self.sender()
        print(ch.parent())
        ix = self.table.indexAt(ch.pos())
        print(ix.row(), ix.column(), ch.isChecked())


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main = Main()
    sys.exit(app.exec_())


Another way to do it is through lambda methods or partial.functions where we pass directly new parameters.

from PyQt5 import QtWidgets, QtGui, QtCore


class Main(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # create table:
        self.table = QtWidgets.QTableWidget()
        self.table.setRowCount(3)
        self.table.setColumnCount(2)
        for i, letter in enumerate("ABC"):
            self.table.setItem(i, 0, QtWidgets.QTableWidgetItem(letter))
        for i in range(self.table.rowCount()):
            ch = QtWidgets.QCheckBox(parent=self.table)
            ch.clicked.connect(lambda checked, row=1, col=i: self.onStateChanged(checked, row, col))
            self.table.setCellWidget(i, 1, ch)
        self.setCentralWidget(self.table)
        self.setWindowTitle('TableWidget, CheckBoxes')
        self.show()

    def onStateChanged(self, checked, row, column):
        print(checked, row, column)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    main = Main()
    sys.exit(app.exec_())

If you want to know more information how to pass extra parameters through connect() you can review this answer.

这篇关于我应该如何在 PyQt5 的 Table Widgets 中连接 CheckBox 单击信号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆