[英]How should I connect CheckBox clicked signals in Table Widgets in PyQt5?
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.基于
table.cellChanged.connect
我天真地期望在复选框更改时会出现cellChanged
信号。 However this signal is not generated.然而,不会产生该信号。 Nor is the
itemChanged
signal. itemChanged
信号也不是。 I can indeed see the clicked
signals, but that is not very useful because it is unclear which checkbox has produced the signal.我确实可以看到
clicked
信号,但这不是很有用,因为不清楚哪个复选框产生了信号。
One way to solve the problem is to create a different checkbox_clicked
function for each checkbox, but that hardly seems elegant.解决该问题的一种方法是为每个复选框创建一个不同的
checkbox_clicked
函数,但这似乎不太优雅。
My questions are:我的问题是:
Why is neither a cellChanged
nor an itemChanged
signal generated when a checkbox is changed?为什么更改复选框时既不生成
cellChanged
也不生成itemChanged
信号?
How should signals be connected in order to know which checkbox has generated the clicked
signal?应该如何连接信号才能知道哪个复选框产生了
clicked
信号?
- Why is neither a cellChanged nor an itemChanged signal generated when a checkbox is changed?
为什么更改复选框时既不生成 cellChanged 也不生成 itemChanged 信号?
because when you use setCellWidget()
a QTableWidgetItem
is not created, and if we check the documentation of cellChanged
and itemChanged
:因为当您使用
setCellWidget()
不会创建QTableWidgetItem
,如果我们检查cellChanged
和itemChanged
的文档:
void QTableWidget::cellChanged(int row, int column)
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)
void QTableWidget::itemChanged(QTableWidgetItem *item)
This signal is emitted whenever the data of item has changed.
每当item的数据发生变化时,就会发出此信号。
- 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.获取方式是间接的,首先要知道的是通过
setCellWidget()
方法添加widget时, QTableWidget
的viewport()
被设置为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()
.另外应该知道的另一件事是,通过
pos()
访问的小部件的位置是相对于父级的,即在我们的例子中相对于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
.有一个非常有用的方法叫做
sender()
,它返回发出信号的对象,在这种情况下它将返回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.由于小部件相对于
viewport()
是已知的,因此它的QModelIndex
是通过indexAt()
方法访问的, QModelIndex
具有单元格的信息。
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.另一种方法是通过 lambda 方法或 partial.functions 直接传递新参数。
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 .如果您想了解更多有关如何通过 connect() 传递额外参数的信息,您可以查看此答案。
use the stateChanged
signal for checkboxes.对复选框使用
stateChanged
信号。
and my take about that code:以及我对该代码的看法:
for example:例如:
from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem, QCheckBox, QApplication
from typing import Dict
class Main(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
# create table:
self.table = QTableWidget()
self.table.insertColumn(0)
self.table.insertColumn(1)
self._items: Dict[QTableWidgetItem, QCheckBox] = {}
for i, tag in enumerate(['A', 'B', 'C']):
self.table.insertRow(i)
item = QTableWidgetItem(tag)
cb = QCheckBox(parent=self.table)
self._items[item] = cb
# set values for first column:
self.table.setItem(i, 0, item)
# add checkboxes to second column:
self.table.setCellWidget(i, 1, cb)
# connect cb signals:
self._items[item].stateChanged.connect(self.checkbox_clicked)
# connect table signals:
self.table.cellChanged.connect(self.cell_changed)
# 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 = QApplication(sys.argv)
main = Main()
app.exec_()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.