PyQt - создание кнопок из словаря - PullRequest
1 голос
/ 22 мая 2011

У меня есть словарь.
Мне нужно создать кнопки с именем ключа, а clicked слот на основе значения:

dic = {'a':'111', 'b':'222', 'c':'333'}

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda: doit(dic[key]))
    vbox.addWidget(btn)

У меня есть все кнопки с правильным названием.И последняя созданная кнопка ведет себя правильно.
Но слоты clicked всех остальных кнопок также связаны с последней созданной кнопкой do('333').

Как заставить все кнопки вести себя по-разному?

Ответы [ 3 ]

3 голосов
/ 22 мая 2011

Анонимная функция lambda: doit(dic[key]) не оценивает key, пока функция не будет вызвана. К этому времени for-loop завершено, а переменная for-loop key ссылается на последний ключ в dic.

Когда вызывается анонимная функция (при нажатии кнопки), в глобальном пространстве имен ищется key, и возвращается текущее значение key.

Чтобы избежать этой ловушки, вы можете использовать аргумент по умолчанию в выражении lambda:

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(lambda key=key: doit(dic[key]))
    vbox.addWidget(btn)

Аргументы по умолчанию оцениваются во время определения , а не во время вызова лямбды. Делая это, key ищется в локальном пространстве имен анонимной функции, а не в глобальном пространстве имен, и поскольку для значения локального пространства имен для ключа установлено значение по умолчанию, которое отличается для каждого прохода через for цикл, вы получите правильное значение для key.

Это также объясняется в этом SO ответе .

1 голос
/ 22 мая 2011

вашей итерации нужны ключи и значения словаря dic.Вы можете использовать метод dict.iteritems ().
Если лямбда сбивает с толку, то лучше использовать частичное.

Попробуйте это:

from PyQt4.QtGui import QApplication, QWidget, QVBoxLayout, QPushButton
from functools import partial

class MainWidget(QWidget):
    def __init__(self):
         super(MainWidget, self).__init__()

         dic = {'a':'111', 'b':'222', 'c':'333'}
         vbox = QVBoxLayout(self)

         for key,val in dic.iteritems():
             btn = QPushButton(key, self)
             btn.clicked.connect(partial(self.doit, val))
             vbox.addWidget(btn)


    def doit(self, text):
        print "%s" % text

if __name__ == "__main__":
    app = QApplication([])
    w = MainWidget()
    w.show()
    app.exec_()
1 голос
/ 22 мая 2011

Я думаю, что проблема в том, что когда вы вызываете lambda: doit (dic [key]), он делает это буквально, и ищет dic [key], и в это время ключ устанавливается равным тому, что последний элемент итерировал, был

попробуйте это:

dic = {'a':'111', 'b':'222', 'c':'333'}

def create_connect(x):
    return lambda: doit(x)

for key in dic:
    btn = QPushButton(key, self)
    btn.clicked.connect(create_connect(dic[key]))
    vbox.addWidget(btn)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...