2016-05-19 2 views
1

私のアプリケーションのためにウィンドウに6つのボタンを配置する必要があります。しかし、アプリケーションが増えるにつれ、より多くのボタンが必要になるかもしれません(多分、7、8、..)。そのため、これらのボタンをPythonリストに入れています。下に私のコードを見ることができます。あなたは、単に/それをコピー&ペーストすることができ、それはエラーなしでお使いのシステム上で実行する必要がありますPyQt4:シグナルスロットメカニズムが 'List of buttons'のために正しく機能しない

私は btnAction(self,n)関数に各ボタンを接続するための標準的なシグナル/スロットメカニズムを使用

enter image description here

import sys 
import os 
from PyQt4 import QtGui 
from PyQt4 import QtCore 

def setCustomSize(x, width, height): 
    sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed) 
    sizePolicy.setHorizontalStretch(0) 
    sizePolicy.setVerticalStretch(0) 
    sizePolicy.setHeightForWidth(x.sizePolicy().hasHeightForWidth()) 
    x.setSizePolicy(sizePolicy) 
    x.setMinimumSize(QtCore.QSize(width, height)) 
    x.setMaximumSize(QtCore.QSize(width, height)) 

'''''' 

class CustomMainWindow(QtGui.QMainWindow): 

    def __init__(self): 

     super(CustomMainWindow, self).__init__() 

     # Define the geometry of the main window 
     self.setGeometry(300, 300, 800, 400) 
     self.setWindowTitle("my first window") 

     # Create FRAME_A 
     self.FRAME_A = QtGui.QFrame(self) 
     self.FRAME_A.setStyleSheet("QWidget { background-color: %s }" % QtGui.QColor(210,210,235,255).name()) 
     self.LAYOUT_A = QtGui.QHBoxLayout() 
     self.LAYOUT_A.setAlignment(QtCore.Qt.AlignLeft) 
     self.FRAME_A.setLayout(self.LAYOUT_A) 
     self.setCentralWidget(self.FRAME_A) 

     # Place the buttons 
     self.placeButtons() 

     self.show() 

    '''''' 

    def placeButtons(self): 
     self.btn = [] 

     for i in range(6): 
      self.btn.append(QtGui.QPushButton(text = 'btn[' + str(i) + ']')) 
      setCustomSize(self.btn[i], 100, 50) 
      self.btn[i].clicked.connect(lambda: self.btnAction(i))    
      self.LAYOUT_A.addWidget(self.btn[i]) 

     '''''' 

    '''''' 


    def btnAction(self,n): 
     print("btn[" + str(n) + "] is clicked") 

    '''''' 



''' End Class ''' 



if __name__== '__main__': 
    app = QtGui.QApplication(sys.argv) 
    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('Plastique')) 
    myGUI = CustomMainWindow() 


    sys.exit(app.exec_()) 

'''''' 

を。ご覧のとおり、私は特別な機能を使用します - それをlambdaフィーチャーと呼んで - パラメータを渡すことができます。パラメータはボタン番号です。

残念ながら、私は関係なく、私がプッシュする何ボタン、次の出力を取得していない:

>>> btn[5] is clicked 
>>> btn[5] is clicked 
>>> btn[5] is clicked 
>>> btn[5] is clicked 

私はへplaceButtons(self)機能を変更:

:今、私は正しい出力を得る

def placeButtons(self): 
     self.btn = [] 

     for i in range(6): 
      self.btn.append(QtGui.QPushButton(text = 'btn[' + str(i) + ']')) 
      setCustomSize(self.btn[i], 100, 50) 
      if(i==0): 
       self.btn[i].clicked.connect(lambda: self.btnAction(0)) 
      elif(i==1): 
       self.btn[i].clicked.connect(lambda: self.btnAction(1)) 
      elif(i==2): 
       self.btn[i].clicked.connect(lambda: self.btnAction(2)) 
      elif(i==3): 
       self.btn[i].clicked.connect(lambda: self.btnAction(3)) 
      elif(i==4): 
       self.btn[i].clicked.connect(lambda: self.btnAction(4)) 
      elif(i==5): 
       self.btn[i].clicked.connect(lambda: self.btnAction(5)) 

      self.LAYOUT_A.addWidget(self.btn[i]) 

     '''''' 

    '''''' 

>>> btn[0] is clicked 
>>> btn[1] is clicked 
>>> btn[2] is clicked 
>>> btn[3] is clicked 

新しいplaceButtons(self)の機能は機能しますが、ただ非常に非効率的で面倒です。誰が最初の(そしてよりクリーンな)実装で何が間違っていたか知っていますか?

注:私はWindows 10で動作し、Python v3を使用し、PyQt4ライブラリ(anacondaパッケージ)で自分のGUIを作成します。

EDITはあなたにミスターありがとうございます。サロモンデロシ。今すぐあなたのソリューションが動作します!私が最初にfunctoolsをインポートする必要があります。

import functools 

次は、私はあなたのソリューションを適用します。

def placeButtons(self): 
     self.btn = [] 

     for i in range(6): 
      self.btn.append(QtGui.QPushButton(text = 'btn[' + str(i) + ']')) 
      setCustomSize(self.btn[i], 100, 50) 
      self.btn[i].clicked.connect(functools.partial(self.btnAction, i)) 
      self.LAYOUT_A.addWidget(self.btn[i]) 

     '''''' 

    '''''' 
+0

ループ内の[QtCore.QObject.connect]の可能な重複は、最後のインスタンスにのみ影響します](http://stackoverflow.com/questions/19510860/qtcore-qobject-connect-in-a-loop-only-affects-the -last-instance) –

+0

こんにちは@three_pineapples、私の質問は確かに "qtcore-qobject-connect- .."と非常によく似ています。これを指摘していただきありがとうございます。それにもかかわらず、私は自分の質問がStackOverflowにとどまるべきだと思う。私は人々が自分のPython IDEにコピー・ペーストして試してみるという完全なコード例を挙げました。私はそれがいくつかの付加価値を与えると信じています。第二に、もう一つの質問には重要なキーワード「シグナルスロット機構」が含まれていません。それはおそらく私が答えを求めてグーグルで見つけなかった理由です。どう思いますか? –

+0

重複した質問は削除されません。ポイントは、実際には、さまざまな検索条件で見つかることができるさまざまなエントリーポイントを提供することですが、答えを1か所にすることができます(したがって、回答を1日に変更する必要がある場合は、50種類の質問回答しかし、チャンスは私の複写旗が必要な票数をとにかく得ることはありません... –

答えて

2

あなたがそれぞれ作成した(ラムダ)関数の値をバインドする必要があります。それを行うには、デフォルト値をパラメータとして渡すことができます。

def test_function(x): 
    return x 


def test(): 
    # DO NOT USE THIS. This is just for showing the effect 
    wrong = list() 
    for i in range(6): 
     wrong.append(lambda: test_function(i)) 

    for w in wrong: 
     print(w()) # will always print 5 

    print("-"*10) 
    # This is the desired behaviour 
    right = list() 
    for i in range(6): 
     right.append(lambda i=i: test_function(i)) 

    for r in right: 
     print(r()) 

if __name__ == '__main__': 
    test() 

次のように出力できます:

5 
5 
5 
5 
5 
5 
---------- 
0 
1 
2 
3 
4 
5 
をここで
for i in range(6): 
    self.btn[i].clicked.connect(lambda i=i: self.btnAction(i)) 

が効果を示すため、最小限の例です。

また、functoolsパッケージのpartialを使用することもできます。

for i in range(6): 
    self.btn[i].clicked.connect(partial(self.btnAction, i)) 
+0

こんにちは。サロモンデロシ。手伝ってくれてどうもありがとう。残念ながら、それは動作しません。私はあなたのソリューションをどのように実装したか、どのような出力が得られるかを示す** EDIT **を投稿しました。 –

+1

@ K.Mulierあなたは正しいです。この場合、関数がなぜFalseを出力するのかわかりません。私は私の答えを更新し、部分的に解決策をテストし、それは正常に動作します – salomonderossi

+0

ありがとうございました!今は完璧に動作します。 –

関連する問題