2016-10-22 5 views
0

何らかの理由で、このコードを実行すると、それぞれの色を個別に切り替えるはずの青色だけが切り替わります。このコードはどのようにして青のみに切り替わりますか? (Python、PyQt)

このコードは、私がちょうど学習を開始したPyQtのチュートリアルであるhttp://eli.thegreenplace.net/2011/04/25/passing-extra-arguments-to-pyqt-slotのサンプルコードの私のバージョンです。

import sys 
from PyQt5.QtWidgets import (QWidget, QPushButton, 
    QFrame, QApplication) 
from PyQt5.QtGui import QColor 


class Example(QWidget): 
    red = False 
    blue = False 
    green = False 
    buttons = [] 

    def __init__(self): 
     super().__init__() 

     self.init_UI() 


    def init_UI(self):  
     self.col = QColor(0, 0, 0) 
     for x in range(0, 3): 
      self.buttons.append(QPushButton('Red' if x == 0 else ('Green' if x == 1 else 'Blue'), self)) 
      self.buttons[x].setCheckable(True) 
      self.buttons[x].move(10, 10 + 50 * x) 
      self.buttons[x].clicked[bool].connect(lambda: self.set_color(x)) 

     self.square = QFrame(self) 
     self.square.setGeometry(150, 20, 100, 100) 
     self.square.setStyleSheet("QWidget { background-color: %s }" % 
      self.col.name()) 

     self.setGeometry(300, 300, 280, 170) 
     self.setWindowTitle('Toggle button') 
     self.show() 

    def set_color(self, button): 
     if button == 0: 
      if self.red == False: 
       self.red = True 
       self.col.setRed(255) 
      else: 
       self.red = False 
       self.col.setRed(0) 
     elif button == 1: 
      if self.green == False: 
       self.green = True 
       self.col.setGreen(255) 
      else: 
       self.green = False 
       self.col.setGreen(0) 
     else: 
      if self.blue == False: 
       self.blue = True 
       self.col.setBlue(255) 
      else: 
       self.blue = False 
       self.col.setBlue(0) 

     self.square.setStyleSheet("QFrame { background-color: %s }" % 
      self.col.name()) 
     print(self.col.name()) 

if __name__ == '__main__': 

    app = QApplication(sys.argv) 
    ex = Example() 
    sys.exit(app.exec_()) 

答えて

1

connect(lambda: self.set_color(x))が動作しない理由はxは、ラムダが呼び出された場合にのみ評価される信号が発せられるとき、すなわち、ずっと後に、ループが完了された後れることです。したがって、set_color()は、信号が放出された時点でxの値を受信します。あなたのコードでは、これはxがループ内に持っていた最後の値になります。

@ Hiの答えは有効ですが、私はAchayanの解(コメントに記載)がより明示的であり、いくつかのコメントに反して - 私は)コードとそれを検証:この作品

for x in range(0, 3): 
    ... 
    self.buttons[x].clicked[bool].connect(partial(self.set_color, x)) 

理由はxは、関数呼び出しの引数(関数はfunctools.partialである)ので、xはすぐ評価されているということです。 fが1つの引数の関数である場合、partial(f, a)によって返される関数は、引数をとらずにf(a)を呼び出す関数g()です。

+0

私のコメントは、「部分的」ではなく、今削除されている回答での「ラムダ」の誤った使用に関するものです。私は正しい使い方をしました。これは 'connect(lambda checked、x = x:self.set_color(x))'です。これは 'clicked '信号によって送られたパラメータの' checked'引数を含んでいるので、実際には 'partial'より明白です。しかし明らかにどちらのソリューションも同様に機能します。 – ekhumoro

関連する問題