为什么这段代码只能切换蓝色? (Python,PyQt)

时间:2016-10-22 15:36:53

标签: python qt pyqt

出于某种原因,运行此代码只会将颜色切换为蓝色,当它应该单独切换每种颜色时。

这段代码是我http://eli.thegreenplace.net/2011/04/25/passing-extra-arguments-to-pyqt-slot示例代码的版本,这是我刚刚开始学习的PyQt教程。

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 个答案:

答案 0 :(得分:2)

connect(lambda: self.set_color(x))不起作用的原因是x仅在调用lambda时才会被评估,即在发出信号之后,在循环完成后将会更晚。因此set_color()会在信号发出时收到x的值。在你的代码中,这将是x在循环中的最后一个值,即2.

虽然@ Hi的回答是有效的,但我发现Achayan的解决方案(在评论中提到)更明确,并且工作得很好(与某些评论相反 - 我用代码验证了它):

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

这可行的原因是x是函数调用的参数(函数为functools.partial),因此x立即计算 。当partial(f, a)是一个arg的函数时,f返回的函数是一个函数g(),它不带参数并调用f(a)