PyQt: 将信号合并到一个槽
我正在尝试减少在上下文菜单中使用的信号数量。这个菜单包含了一些操作,这些操作可以切换程序的工作模式,所以这些操作的实现其实很简单。根据QMenu::triggered的文档,
通常,你会把每个菜单项的triggered()信号连接到它自己特定的槽函数,但有时候你可能想把几个动作连接到同一个槽,比如当你有一组紧密相关的动作,比如“左对齐”、“居中”、“右对齐”。
不过,我不知道该怎么做,文档里也没有更详细的说明。
假设我在菜单actionMenu
中有两个动作actionOpMode1
和actionOpMode2
,还有一个槽函数setOpMode
。我希望在调用setOpMode
时,能够传入一个参数,这个参数能表明是哪个动作被触发了。我尝试了各种不同的方式来实现这个目标:
QObject.connect(self.actionMenu, SIGNAL('triggered(QAction)'), self.setOpMode)
但我甚至没有成功调用setOpMode
,这说明actionMenu
似乎从来没有“被触发”,可以这么说。
在这个SO问题中,有人建议可以用lambda表达式来实现,但这样:
QObject.connect(self.actionOpMode1, SIGNAL('triggered()'), lambda t: self.setOpMode(t))
却给出了"<lambda> () takes exactly 1 argument (0 given)"
的错误提示。我不能说我完全理解这个是怎么工作的,所以在从clicked()切换到triggered()时,我可能做错了什么。
那该怎么做呢?
3 个回答
你可以使用 QObject::sender() 来找出哪个 QAction 发出了信号。
所以你的槽函数可能看起来像这样:
def triggered(self):
sender = QtCore.QObject.sender()
if sender == self.actionOpMode1:
# do something
elif sender == self.actionOpMode2:
# do something else
关于你提到的另一个 StackOverflow 问题,里面用到了 lambda,简单来说,它创建了一个带有默认值的参数的 lambda。如果要把它应用到你的例子中,你需要这样做:
self.connect(self.actionOpMode1, QtCore.SIGNAL('triggered()'), lambda who="mode1": self.changeMode(who))
self.connect(self.actionOpMode2, QtCore.SIGNAL('triggered()'), lambda who="mode2": self.changeMode(who))
然后你可以有一个这样的成员函数:
def changeMode(self, who):
if who == "mode1":
# ...
elif who == "mode2":
# ...
我个人觉得第一种方法看起来更简洁、更易读。
我使用这种方法:
from functools import partial
def bind(self, action, *params):
self.connect(action, QtCore.SIGNAL('triggered()'),
partial(action, *params, self.onMenuAction))
def onMenuAction(self, *args):
pass
bind(self.actionOpMode1, 'action1')
bind(self.actionOpMode2, 'action2')
使用QObject.Sender是一个解决办法,虽然不是最干净的方式。
可以使用QSignalMapper,这样可以更清晰地将一个值和发出信号的对象关联起来。