PyQt5动态生成QCheckBox绑定事件异常问题求助
解决PyQt5动态绑定QCheckBox状态变化事件的异常问题
这个问题我之前踩过坑,本质是Python lambda的迟绑定特性在搞鬼!
问题根源
你在循环里写的lambda:self.checkboxState(checkbox)并没有在循环迭代时就捕获当前的checkbox对象,而是在lambda函数实际被调用(也就是复选框状态变化)的时候,才去查找checkbox变量的当前值。等循环结束后,checkbox变量已经指向最后一个创建的QCheckBox实例(也就是Demo3那个),所以不管你点哪个复选框,最终传入checkboxState的都是最后那个对象。
两种实用解决方法
方法1:用lambda默认参数捕获当前对象
修改循环里的绑定代码,给lambda添加一个默认参数,把当前迭代的checkbox赋值给这个参数。这样每次循环时,默认参数会立刻捕获当时的checkbox实例,而不是等到调用时再去查找:
import sys from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication, QCheckBox, QButtonGroup, QAbstractButton) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def checkboxState(self,b): if b.isChecked() == True: print(b.text()+ " is selected") else: print(b.text()+ " is deselected") def initUI(self): grid = QGridLayout() self.setLayout(grid) appList = ['Demo1','Demo2','Demo3'] for app in appList: checkbox = QCheckBox(app) # 用默认参数捕获当前的checkbox实例,_用来接收stateChanged传递的状态值 checkbox.stateChanged.connect(lambda _, chk=checkbox:self.checkboxState(chk)) grid.addWidget(checkbox) self.move(300, 150) self.setWindowTitle('Checkbox Demo') self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
这里的_是用来接收stateChanged信号自带的状态参数(比如Qt.Checked),避免参数不匹配导致的隐性问题。
方法2:使用functools.partial绑定参数
另一种更直观的方式是用functools.partial来固定回调函数的参数,明确把当前的checkbox绑定到checkboxState方法上:
import sys from functools import partial from PyQt5.QtWidgets import (QWidget, QGridLayout, QPushButton, QApplication, QCheckBox, QButtonGroup, QAbstractButton) class Example(QWidget): def __init__(self): super().__init__() self.initUI() def checkboxState(self,b): if b.isChecked() == True: print(b.text()+ " is selected") else: print(b.text()+ " is deselected") def initUI(self): grid = QGridLayout() self.setLayout(grid) appList = ['Demo1','Demo2','Demo3'] for app in appList: checkbox = QCheckBox(app) # 用partial绑定当前的checkbox作为参数 checkbox.stateChanged.connect(partial(self.checkboxState, checkbox)) grid.addWidget(checkbox) self.move(300, 150) self.setWindowTitle('Checkbox Demo') self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_())
验证效果
修改后运行代码,不管你勾选或取消哪个复选框,控制台都会正确输出对应复选框的文本和状态,比如勾选Demo1时会打印Demo1 is selected,取消勾选时打印Demo1 is deselected,完全符合预期。
内容的提问来源于stack exchange,提问作者Shandon Anderson
相关产品推荐
相关产品推荐

