PyQt5用getattr绑定按钮点击事件导致self为布尔值的报错问题
解决PyQt5动态绑定按钮点击事件时的AttributeError问题
问题描述
在PyQt5中使用getattr()动态绑定按钮点击事件,运行时出现错误AttributeError: 'bool' object has no attribute 'key',不清楚为何self实例被赋值为布尔值。实际场景中有大量按钮,希望通过动态方式绑定而非逐个编写绑定代码,示例代码如下:
import sys from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QLabel class MyApp(QWidget): def __init__(self): super().__init__() self.ui() key = 0 btns = ["Next", "Back"] def ui(self): for a in range(0, 2): btn = QPushButton(self.btns[a], self) btn.move(20, 20 * a + 10) btn.clicked.connect(getattr(MyApp, self.btns[a])) #//////////////////////////////// it's only UI ////////////////////////////////// self.setWindowTitle('Question') self.setGeometry(100, 100, 100, 100) self.label1 = QLabel('0', self) self.label1.move(20, 60) self.show() #//////////////////////////////////////////////////////////////////////////////// def Next(self): if self.key < 5: self.key += 1 self.label1.setText(self.key) def Back(self): if 1 <= self.key: self.key -= 1 self.label1.setText(self.key) #//////////////////////////////////////////////////////////////////////////////// if __name__ == '__main__': app = QApplication(sys.argv) ex = MyApp() sys.exit(app.exec_())
报错信息:
Traceback (most recent call last): File "C:\project\pyeditor\QnA.py", line 31, in Next if self.key < 5: AttributeError: 'bool' object has no attribute 'key'
错误原因
- 方法绑定错误:代码中用
getattr(MyApp, self.btns[a])绑定的是类的方法,而非当前实例的方法。Qt的clicked信号默认会传递一个布尔参数(表示按钮是否处于按下状态),信号触发时这个布尔值会被当作第一个参数传入方法,直接覆盖了方法定义中的self参数,导致方法内的self变成布尔值,从而引发属性错误。 - 类型不匹配:
self.label1.setText(self.key)中,setText()要求传入字符串类型,但直接传入整数self.key会触发类型错误。
解决方法
- 绑定实例方法:改用
getattr(self, self.btns[a])获取当前实例的方法,同时用lambda包装方法以忽略clicked信号传递的布尔参数,避免参数覆盖self。 - 类型转换:将整数
self.key转换为字符串后再传入setText()。
修改后的代码
import sys from PyQt5.QtWidgets import QApplication, QPushButton, QWidget, QLabel class MyApp(QWidget): def __init__(self): super().__init__() self.key = 0 # 改为实例变量,避免多实例共享数据问题 self.btns = ["Next", "Back"] self.ui() def ui(self): for idx, btn_text in enumerate(self.btns): btn = QPushButton(btn_text, self) btn.move(20, 20 * idx + 10) # 用lambda包装方法,忽略clicked信号的布尔参数 btn.clicked.connect(lambda _, func=getattr(self, btn_text): func()) self.setWindowTitle('Question') self.setGeometry(100, 100, 100, 100) self.label1 = QLabel('0', self) self.label1.move(20, 60) self.show() def Next(self): if self.key < 5: self.key += 1 self.label1.setText(str(self.key)) # 转换为字符串类型 def Back(self): if self.key >= 1: self.key -= 1 self.label1.setText(str(self.key)) # 转换为字符串类型 if __name__ == '__main__': app = QApplication(sys.argv) ex = MyApp() sys.exit(app.exec_())
额外优化:将key和btns从类变量改为实例变量,避免多个实例之间共享同一数据的问题;使用enumerate遍历按钮文本,代码更简洁易读。
内容的提问来源于stack exchange,提问作者Kim G'bril Jibin
相关产品推荐
相关产品推荐

