QMenu的QAction无法同时传递checked状态和自定义参数到关联槽函数
问题核心原因
- Python 闭包的迟绑定特性:循环内定义的lambda如果直接引用循环变量
index,只有lambda实际执行时才会读取index的值,此时循环已执行完毕,index固定为最后一次的迭代值2。 - Qt
QAction.triggered信号存在重载:默认会优先匹配无参版本triggered(),只有显式指定时才会使用带勾选状态的triggered(bool)版本,这也是你第二个写法报参数缺失、第三个写法checked永远为False的根本原因。
正确写法
你只需要显式指定triggered信号的bool重载,同时用默认参数绑定每次循环的index值即可,修改后的核心代码如下:
for index, label in enumerate(labels): # 显式指定信号的bool重载,用默认参数绑定当前迭代的index值 slot = lambda checked, i=index: self.run_menu_item(checked, i) action = QAction(label, self) action.setCheckable(True) # 先设置可勾选,再绑定信号逻辑更合理 action.triggered[bool].connect(slot) self.dynamic_menu.addAction(action)
如果你觉得lambda写法容易出错,也可以用functools.partial实现,逻辑更直观:
# 头部导入模块 from functools import partial # 循环内的槽函数定义 slot = partial(self.run_menu_item, index=index) action.triggered[bool].connect(slot) # 对应槽函数不需要做额外修改 @QtCore.Slot(bool, int) def run_menu_item(self, checked, index): print('checked:{} index:{}'.format(checked, index))
完整可运行示例
import sys from PySide2 import QtCore from PySide2.QtWidgets import (QMainWindow, QApplication, QAction) class Window(QMainWindow): def __init__(self, parent=None): super().__init__(parent) # create menu self.dynamic_menu = self.menuBar().addMenu('tools') # add menu items labels = ['tool0', 'tool1', 'tool2'] for index, label in enumerate(labels): slot = lambda checked, i=index: self.run_menu_item(checked, i) action = QAction(label, self) action.setCheckable(True) action.triggered[bool].connect(slot) self.dynamic_menu.addAction(action) @QtCore.Slot(bool, int) def run_menu_item(self, checked, index): print('checked:{} index:{}'.format(checked, index)) if __name__ == '__main__': app = QApplication(sys.argv) window = Window() window.setMinimumSize(400, 100) print('starting app...') window.show() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者NZD
相关产品推荐
相关产品推荐

