Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал. [RSS Feed]

#1 Март 8, 2015 13:38:36

Pluto
Зарегистрирован: 2012-05-29
Сообщения: 177
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

from PyQt4 import QtGui
class win(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        
        self.lay = QtGui.QVBoxLayout()
        self.setLayout(self.lay)
        
        self.mass = [{"obj":None, "name":"one", "text":"Первая кнопка", "val":1},
                   {"obj":None, "name":"two", "text":"Вторая кнопка", "val":2}]
        for i in self.mass:
            i["obj"] = QtGui.QPushButton(i["text"])
            i["obj"].setObjectName(i["name"])
            self.lay.addWidget(i["obj"])
            i["obj"].clicked.connect(lambda: self.myfunc(i["val"])) # как тут сделать-то?
    def myfunc(self, val):
        print (str(val))
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window = win()
    window.show()
    sys.exit(app.exec_())

Кнопки прекрасно создаются, каждая как отдельный объект. А вот связать каждую кнопку с методом не выходит. Лямбда-блямбда, в итоге, для всех кнопок передаёт последнее значение из списка. Т.е. при нажатии на первую кнопку на экране должна бы появляться единичка, но вторую - двойка; а выходит так, что куда не тычь - получишь двойку.
Как победить?

Офлайн

#2 Март 8, 2015 16:02:21

vrabey
От: Киев
Зарегистрирован: 2013-04-17
Сообщения: 209
Репутация: +  23  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

в цикле значение i на каждой итерации перезаписывается

for i in range(3):
    pass
print i

нужно как нибудь хранить промежуточное состояние
lst = []
for i in range(3):
    lst.append(i)
print lst[0]

Отредактировано vrabey (Март 8, 2015 16:11:50)

Офлайн

#3 Март 8, 2015 16:27:34

Pluto
Зарегистрирован: 2012-05-29
Сообщения: 177
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

Что-то не пойму.
Как это применимо к моей программе?
i на каждой итерации содержит ссылку на словарь из списка. Я использую значения именно из словаря.

Офлайн

#4 Март 8, 2015 16:31:05

Pluto
Зарегистрирован: 2012-05-29
Сообщения: 177
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

или мне надо в каждый словарь ещё и лямбду как отдельный элемент засунуть и к нему сигналы кнопок коннектить?

Офлайн

#5 Март 8, 2015 16:39:41

Pluto
Зарегистрирован: 2012-05-29
Сообщения: 177
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

from PyQt4 import QtGui
class win(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        
        self.lay = QtGui.QVBoxLayout()
        self.setLayout(self.lay)
        
        self.mass = [{"obj":None, "name":"one", "text":"Первая кнопка", "val":lambda:self.myfunc(1)}, # эвона как!
                   {"obj":None, "name":"two", "text":"Вторая кнопка", "val:"lambda:self.myfunc(2)}]
        for i in self.mass:
            i["obj"] = QtGui.QPushButton(i["text"])
            i["obj"].setObjectName(i["name"])
            self.lay.addWidget(i["obj"])
            i["obj"].clicked.connect(i["val"]) # вот так срабатывает верно
    def myfunc(self, val):
        print (str(val))
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window = win()
    window.show()
    sys.exit(app.exec_())

Вот так работает как надо, только выглядит это как-то…

Кто объяснит как оно так в питоне работает-то в моём первом варианте? Там что, получается, создавалась, а потом переопределялась одна и та же lambda-функция что ль? Которая, в последней своей модификации, оказалась привязана ко всем кнопкам. А почему одна и та же?

А как-то по-другому, более красиво сию ситуацию разрулить можно?

Отредактировано Pluto (Март 8, 2015 16:42:06)

Офлайн

#6 Март 8, 2015 16:46:04

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

Ну первое, что приходит в голову это замыкания

import sys
from PyQt4 import QtGui
 
 
def wrapper(*args):
    def myfunc():
        print(*args)
    return myfunc
 
 
class Window(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.lay = QtGui.QVBoxLayout()
        self.setLayout(self.lay)
        self.mass = [{"obj": None, "name": "one", "text": "Первая кнопка", "val": 1},
                     {"obj": None, "name": "two", "text": "Вторая кнопка", "val": 2}]
        for i in self.mass:
            i["obj"] = QtGui.QPushButton(i["text"])
            i["obj"].setObjectName(i["name"])
            self.lay.addWidget(i["obj"])
            i["obj"].clicked.connect(wrapper(i["val"]))
 
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

Офлайн

#7 Март 8, 2015 16:50:22

alex925
Зарегистрирован: 2015-01-08
Сообщения: 204
Репутация: +  14  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

Твой код с lambda не работает, потому что lambda реализует ленивые вычисления, то есть функция инициализируется в не в момент её создания, а момент вызова (и получается, что все созданные функции инициализируются с последним значением переменной цикла).
Именно по этому в цикле анонимные функции для откладывания вызова функции использовать не получится.

Отредактировано alex925 (Март 8, 2015 17:01:52)

Офлайн

#8 Март 8, 2015 17:06:35

vrabey
От: Киев
Зарегистрирован: 2013-04-17
Сообщения: 209
Репутация: +  23  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

так можно

from functools import partial # <<<
from PyQt4 import QtGui
class win(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self.lay = QtGui.QVBoxLayout()
        self.setLayout(self.lay)
        self.mass = [{"obj":None, "name":"one", "text":u"Первая кнопка", "val":1},
                   {"obj":None, "name":"two", "text":u"Вторая кнопка", "val":2}]
        for i in self.mass:
            i["obj"] = QtGui.QPushButton(i["text"])
            i["obj"].setObjectName(i["name"])
            self.lay.addWidget(i["obj"])
            i["obj"].clicked.connect(partial (self.myfunc, i["val"])) # <<<
    def myfunc(self, val):
        print (str(val))
if __name__ == "__main__":
    import sys
    app = QtGui.QApplication(sys.argv)
    window = win()
    window.show()
    sys.exit(app.exec_())

Отредактировано vrabey (Март 8, 2015 17:07:17)

Офлайн

#9 Март 8, 2015 17:47:35

Pluto
Зарегистрирован: 2012-05-29
Сообщения: 177
Репутация: +  1  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

Спасибо всем ответившим.
Vrabey отдельное БОЛЬШОЕ спасибо! Все проблемы с этим способом решились.
Приведённый тут мной пример был упрощен. В оригинальном коде мне понадобилось в качестве аргумента передать вообще ссылку на весь словарь, а не на отдельное значение его. И получилось без проблем!
partial - наше всё.

Офлайн

#10 Март 9, 2015 02:20:33

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 9716
Репутация: +  842  -
Профиль   Отправить e-mail  

PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.

Pluto
i["obj"].clicked.connect(lambda: self.myfunc(i["val"])) # как тут сделать-то?

i["obj"].clicked.connect(lambda e, i=i: self.myfunc(i["val"]))

[guest@localhost py]$ ./t.py 
1
2
1
2
[guest@localhost py]$



Отредактировано py.user.next (Март 9, 2015 02:22:22)

Офлайн

  • Начало
  • » GUI
  • » PyQt4. Динамическое создание кнопок. Проблема с передачей атрибута через сигнал.[RSS Feed]

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version