2009-06-30 67 views
2

我試圖減少我在contextmenus中使用的信號量。菜單由切換程序操作模式的動作組成,因此插槽執行的操作非常簡單。報價上QMenu的文檔::觸發,PyQt:將信號合併到一個插槽

通常情況下,每個菜單動作的觸發()信號連接到它自己的定製插槽,但有時你會想幾個動作,當連接到一個單一的插槽,例如你有一組密切相關的行爲,例如「左對齊」,「中心」,「右對齊」。

但是,我不知道如何做到這一點,文件沒有進一步的細節。
假設我在菜單actionMenu中有動作actionOpMode1actionOpMode2,以及插槽setOpMode。我想用一個參數來調用setOpMode,這個參數與某些操作相關。我想在這個主題上不同的排列:

QObject.connect(self.actionMenu, SIGNAL('triggered(QAction)'), self.setOpMode) 

但我從來沒有得到它叫setOpMode,這表明actionMenu從來沒有「感覺觸發」,可以這麼說。

this SO question,它的建議,它可以與lamdbas來完成,但是這樣的:

QObject.connect(self.actionOpMode1, SIGNAL('triggered()'), lambda t: self.setOpMode(t)) 

"<lambda>() takes exactly 1 argument (0 given)"。我不能說我真的明白這應該如何工作,所以我從clicked()移動到triggered()時可能做錯了什麼。

它是如何完成的?

回答

4

使用QObject.Sender是解決方案之一,雖然不是最乾淨的一個。

使用QSignalMapper將一個值與發出信號的對象完全關聯。

+0

+1,QSignalMapper的設計非常適合這個目的(我認爲它也非常優雅),所以它提供了架構解決方案。 – 2009-06-30 15:34:17

1

您可以使用QObject::sender()來確定哪個QAction發出信號。

所以你的插槽可能是這樣的:

def triggered(self): 
    sender = QtCore.QObject.sender() 

    if sender == self.actionOpMode1: 
     # do something 
    elif sender == self.actionOpMode2: 
     # do something else 

關於正在發生的事情在其他SO質疑你的拉姆達提到的,它的作用是創建具有默認值,因此一個參數的拉姆達以應用到你的例子你需要做這樣的事情:

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": 
     # ... 

個人而言,第一種方法看起來更清潔,更易讀。

+1

connect()不增加接收者的引用次數;除非持有額外的參考,否則不能在連接中使用lambda。 – 2010-11-12 23:22:10

2

我用這個辦法:

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')