Форум сайта python.su
В книге http://infohost.nmt.edu/tcc/help/pubs/tkinter/tkinter.pdf (pdf, 1,4Мб) на стр.115 (“30.7. The extra arguments trick”) имеет место фрагмент кода с десятью checkbutton'ами которые создаются в цикле и к каждой в том же цикле привязывается своё событие.
Пытаюсь повторить это, но получается, что сгенерированный в цикле handler существует для всех виджетов только в том виде, в каком он генерится в последнем цикле.
Создаю в цикле 5 чекбатонов, ниже вывожу для наглядности переменную данного чекбатона (0 или 1). При снятии или проставке “галочки” с чекбатона срабатывает handler, для проверки в консоль выводится аргумент с которым этот handler срабатывает и это всегда номер последнего шага в цикле, а нужен номер того шага, в котором был сгенерён данный виджет.
Не пойму где моё художество спотыкается. Мозг свело.
Вот пример как он есть в книге:
def __createWidgets ( self ):
...
self.cbList = [] # Create the checkbutton list
for i in range(10):
cb = Checkbutton ( self, ... )
self.cbList.append ( cb )
cb.grid( row=1, column=i )
def handler ( event, self=self, i=i ):
return self.__cbHandler ( event, i )
cb.bind ( "<Button-1>", handler )
...
def __cbHandler ( self, event, cbNumber ):
...
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Tkinter import *
class App(Frame):
def __init__(self,master=None):
Frame.__init__(self, master)
self.grid()
self.chcks=[]
self.dots=[]
self.status_=[]
#в цикле создаю чекбаттоны и их переменные
for step in range(1,6):
self.chk=Checkbutton()
self.chk.grid(row=0,column=step)
self.dot=IntVar()
self.dot.set(0)
self.chk["variable"]=self.dot
def handler (event, self=self, x=step):
#примитивная проверка
print ">>>>>>>>>>handler№ ", step
return self.__statset (event, step)
self.chk.bind ("<1>", handler)
self.statusbar=Label() #current dot display
self.statusbar.grid(row=1,column=step)
self.statusbar["textvariable"]=self.dot
self.dots.append(self.dot) #appending things into lists
self.chcks.append(self.chk)
self.status_.append(self.statusbar)
self.svar=StringVar() #summary variable
self.svar.set(self.dots[2].get())
self.summ=Label() #summary display
self.summ.grid(row=2,column=0)
self.summ["textvariable"]=self.svar
def __statset(self, num):
self.svar.set(num)
root=App()
root.mainloop()
Офлайн
Вы не создаете разные чекбатоны в цикле, вы несколько раз создаете один и тот же, каждый раз заменяя предыдущий. Сделайте список чекбатонов, примерно так:
self.chk=range(1,6)
for step in range(1,6):
self.chk[step]=Chekbutton()
self.chk[step].grid(row=0,column=step)
# и так далее
Офлайн
def handler ( event, self=self, i=i ):
return self.__cbHandler ( event, i )
def handler (event):
self.__cbHandler (event, i)
Отредактировано (Май 31, 2010 10:03:11)
Офлайн
Попробовал применить оба ваши совета, сообщений об ошибках теперь не выводится, но всё равно сгенерированный в цикле handler работает только как генерированный в последнем шаге цикла.
GriffonЯ попробовал чекбаттоны и их переменные создавать как советует igor.kaist, а метки отражающие эти переменный по-старому т.е. создаю переменную и присоединяю её к списку append'ом и в обоих случаях оно работало.
upd: Насколько я помню, при выполнении grid ссылка на обьект сохраняется, и переменную можно смело освобождать, если не планируется потом ей оперировать.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#сообщения об ошибке больше нет, но созданный в цикле handler заменяется
#сгенерированным в последнем шаге цикла т.е. в консоли вечно "handler №5"
from Tkinter import *
class App(Frame):
def __init__(self,master=None):
Frame.__init__(self, master)
self.grid()
self.chks=[] #checkbuttons list
self.chks=range(1,7)
self.dots=[] #chekbutton's variables list
self.dots=range(1,7)
self.status_=[]# "statusbar" labels list
for step in range(1,6): #create checkbuttons and their vars
self.chks[step]=Checkbutton()
self.chks[step].grid(row=0,column=step)
self.dots[step]=IntVar()
self.chks[step]["variable"]=self.dots[step]
def handler (event, self=self): #примитивная проверка
print ">>>>>>>>>>handler№ ", step
return self.__statset (step) #set variable of self.summ Label
self.chks[step].bind ("<1>", handler)
self.statusbar=Label() #current dot display
self.statusbar.grid(row=1,column=step)
self.statusbar["textvariable"]=self.dots[step]
#self.dots.append(self.dots) #appending things into lists
#self.chks.append(self.chks)
self.status_.append(self.statusbar)
self.svar=StringVar()
self.summ=Label()
self.summ.grid(row=2,column=0)
self.summ["textvariable"]=self.svar
def __statset(self, num):
self.svar.set(num)
root=App()
root.mainloop()
ls=[] #типа список
ls=range(1,6) #заполняю его range'ом
ls
[1, 2, 3, 4, 5]
step=range(1,6)
type(step)
<type 'list'>
for step in range(1,6):
...: ls[step]=step
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
ls
[1, 1, 2, 3, 4]
def handler (event, self=self): #примитивная проверка
print ">>>>>>>>>>handler№ ", step
print event.widget
return self.__statset (step) #set variable of self.summ Label
self.chks[step].bind ("<1>", handler)
Отредактировано (Июнь 3, 2010 20:26:54)
Офлайн
def handler (event, self=self, step=step) и будет тебе счастье.
Офлайн
Спасибо. Стало мне счастье.
Офлайн