LINUX.ORG.RU

pyqt: если связывать сигналы со слотами в цикле, связывается с одним слотом


0

1

Помогите разобраться
Почему следующий код создает окошко с 10 кнопками, при нажатии на каждую из которых выводится 9? (Я ожидал, что будет выводится номер кнопки)

https://gist.github.com/731266



Последнее исправление: nbdarvin (всего исправлений: 1)
Ответ на: комментарий от fluorite

бр... a = SomeClass() a.some_thing = 11 some_list.append(a) a = OtherClass()

print some_list[0].some_thing выводит 11! что ж не так?

nbdarvin
() автор топика

http://codepad.org/jsAAOVXf

x = 10
f = lambda: x
print f() # 10
x = 20
print f() # 20

f = lambda y: lambda: y
f = f(x)
print f() # 20
x = 30
print f() # 20

x = []
for i in range(10):
    x += [lambda: i]

for j in range(10):
    print x[j](),

for i in range(10):
    print x[i](),

def ident(a):
    return lambda: a

print '--'
x = []
for i in range(10):
    x += [ident(i)]

for j in range(10):
    print x[j](),

for i in range(10):
    print x[i](),

rival ★★
()
Ответ на: комментарий от rival

я тупой. вроде разобрался, как этот код работает, спасибо. как это в мой код код красивше вписать, не пойму, час уже думаю

nbdarvin
() автор топика

Вообще говоря, должен быть механизм соединения слота с пользовательскими параметрами, но с ходу почему-то его не нашел, то есть как-то так:

b.clicked.connect(self.echo, i)

Товарищи кьютисты, неужели все действительно плохо с сигналами?

А в твоем случае из положения можно выйти так:

from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys

class MainForm(QWidget):
    def __init__(self):
        super(MainForm, self).__init__()
        layout = QVBoxLayout()
        self.setLayout(layout)

        def make_echo(i):
            return lambda: self.echo(i)

        for i in range(10):
            b = QPushButton(str(i))
            self.layout().addWidget(b)
            b.clicked.connect(make_echo(i))
    
    def echo(self, i):
        print i
        return 0

if __name__=="__main__":
    app = QApplication(sys.argv)
    w = MainForm()
    w.show()

    sys.exit(app.exec_())

baverman ★★★
()
Ответ на: комментарий от baverman

> Вообще говоря, должен быть механизм соединения слота с пользовательскими параметрами, но с ходу почему-то его не нашел

Наверное потому, что в Qt (C++) нет «пользовательских параметров». А вот в питоне есть замыкания, с помощью которых эти пользовательские параметры можно вполне успешно реализовать. На C++ вероятно можно как-то извратиться, но сходу не придумаю как.

rival ★★
()

В начале: import functools
Строку 13:
b.clicked.connect(lambda: self.echo(i))
заменить на:
b.clicked.connect(functools.partial(self.echo, i))

Всё.

excelsior
()
Ответ на: комментарий от excelsior

functools.partial

Или так, да, постоянно забываю что в стандартной библиотеке уже все есть.

baverman ★★★
()
Ответ на: комментарий от baverman

Такой вариант мне симпатичнее:

        def make_button(i):
          b = QPushButton(str(i))
          self.layout().addWidget(b)
          b.clicked.connect(lambda: self.echo(i))
        map(make_button, range(10))

rival ★★
()
Ответ на: комментарий от rival

А мне такой:

import gtk

def echo(btn, i):
    print i

w = gtk.Window(gtk.WINDOW_TOPLEVEL)
w.connect('delete-event', lambda *args:gtk.main_quit())

box = gtk.VBox()

for i in range(10):
    btn = gtk.Button(str(i))
    btn.connect('clicked', echo, i)
    box.pack_start(btn)

w.add(box)
w.show_all()

gtk.main()
baverman ★★★
()
Ответ на: комментарий от baverman

> Вообще говоря, должен быть механизм соединения слота с пользовательскими параметрами

QSignalMapper

unC0Rr ★★★★★
()
Ответ на: комментарий от unC0Rr

QSignalMapper

Да, оно, но api страашненький и если на плюсах он органичен, то в питоне действительно легче сделать замыкание.

baverman ★★★
()
Ответ на: комментарий от baverman

Абсолютно согласен, хоть мне и приходится писать на цпп, у питона вижу явные преимущества в этом плане

unC0Rr ★★★★★
()

можно добавить кнопке своё свойство, потом в обработчике его получить. не подойдёт?

arsi ★★★★★
()
Ответ на: комментарий от excelsior

>b.clicked.connect(lambda: self.echo(i))

заменить на:

b.clicked.connect(functools.partial(self.echo, i))

Проще, наверное, b.clicked.connect(lambda x=i: self.echo(x))

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.