Найти - Пользователи
Полная версия: Tkinter Button + lambda-функция
Начало » GUI » Tkinter Button + lambda-функция
1 2 3
Paranoia_Agent
Здравствуйте, недавно натолкнулся на такую вещь, опишу в виде примера:
Необходимо создать несколько одинаковых кнопок с одной функцией, но разными аргументами. Первое, что пришло мне в голову было что-то вот такое:
import Tkinter
def f(x,y):
    print(x+y)
root=Tkinter.Tk()
for x in range(10):
    for y in range(10):
        Tkinter.Button(root,text=str(x)+'+'+str(y),command=lambda:f(x,y)).grid(row=x, column=y)
root.mainloop()
но при ближайшем рассмотрении оказалось, что лямбда-функция вызывается только при нажатии на кнопку (что, кстати, логично) и значения x и y подставляются последние, да и то если они еще не затерлись (что тоже логично). Единственное, что я смог придумать - это создать класс, например такой:
import Tkinter
class but:
    def __init__(self,x,y):
        Tkinter.Button(root,text=str(x)+'+'+str(y),command=lambda:self.f(x,y)).grid(row=x, column=y)
    def f(self,x,y):
        print (x+y)
root=Tkinter.Tk()
for x in range(10):
    for y in range(10):
        but(x,y)
root.mainloop()
Как все же правильно написать?
4kpt_III
Нужно явно передавать. Тогда не будут затираться.
Ваш пример:

import Tkinter
def f(x, y):
    print(x + y)
root = Tkinter.Tk()
for x in range(10):
    for y in range(10):
        Tkinter.Button(root, text = str(x) + '+' + str(y), command=lambda x=x, y=y: f(x,y)).grid(row=x, column=y)
root.mainloop()

P.S. Будут вопросы - пишите…
Paranoia_Agent
4kpt_III
Спасибо, стало понятно.
Еще решил попробовать сделать вкладочки и, почитав этот топик, кстати с вашими ответами: http://python.su/forum/topic/21802/, написал вот это (фреймы специально не удаляются, а скрываются, т.к. к ним может быть обращение с других вкладок) :
import Tkinter
import ttk
def go(index, frobj, butobj):
    global active
    frobj[active].grid_remove()
    frobj[index].grid(row = 0, column = 2, rowspan=10)
    butobj[active].config(bg="white")
    butobj[index].config(bg="yellow")
    active = index
root=Tkinter.Tk()
but=[]
fr=[Tkinter.Frame(root) for x in range(5)]
Tkinter.Label(fr[0],text="I`m label").grid(row = 0, column = 0)
Tkinter.Frame(fr[1],bg="red", height=200, width=600).grid(row = 0, column = 0)
Tkinter.Button(fr[2],text="I`m button :D").grid(row = 0, column = 0)
Tkinter.Frame(fr[3],bg="yellow", height=100, width=200).grid(row = 0, column = 0)
Tkinter.Text(fr[4], height=10, width=20).grid(row = 0, column = 0)
for x in xrange(9):
    if x%2 == 0:
        but.append(Tkinter.Button(root, text="Button", command=lambda y=int(x/2), fr=fr: go(y,fr,but), bd=0, height=2, width=10, bg="white"))
        but[int(x/2)].grid(row = x, column = 0)
    else:
        ttk.Separator(root, orient="horizontal").grid(row = x, column = 0, sticky="ew")
s = ttk.Separator(root, orient="vertical")
s.grid(row = 0, column = 1, rowspan=10, sticky="ns")
global active
active=1
go(0, fr, but)
root.mainloop()
Теперь вопросики:
- Как избавиться от global?
- Как убрать изменение размера окна при нажатии на кнопки? Нужно установить размер окна по максимальному из фреймов, размеры которых точно сказать невозможно.
- Как получить цвет стандартного фона? Есть такая функция в tkinter color, но я что-то её забыл.
4kpt_III
Тут два варианта. Либо ООП, либо явно передавать в lambda.
terabayt
4kpt_III
либо явно передавать в lambda.
но в функции изменяется переменная
active = index
а вот ООП это и выход и правильно
Paranoia_Agent
Получилось как-то так:
import Tkinter
import ttk
class button_note:
    def __init__(self,root):
        self.but=[]
        self.enabled=0
        for index in xrange(9):
            if index%2 == 0:
                self.but.append(Tkinter.Button(root,text="Button", command=lambda x=int(index/2): self.enable(x), bd=0, height=2, width=10, bg="white"))
                self.but[int(index/2)].grid(row = index, column = 0)
            else:
                ttk.Separator(root, orient="horizontal").grid(row = index, column = 0, sticky="ew")
        self.fr=[Tkinter.Frame(root) for x in range(5)]
        Tkinter.Label(self.fr[0],text="I`m label").grid(row = 0, column = 0)
        Tkinter.Frame(self.fr[1],bg="red", height=200, width=600).grid(row = 0, column = 0)
        Tkinter.Button(self.fr[2],text="I`m button :D").grid(row = 0, column = 0)
        Tkinter.Frame(self.fr[3],bg="yellow", height=100, width=200).grid(row = 0, column = 0)
        Tkinter.Text(self.fr[4], height=10, width=20).grid(row = 0, column = 0)
        ttk.Separator(root, orient="vertical").grid(row = 0, column = 1, rowspan=10, sticky="ns")
        self.enable(self.enabled)
    def enable(self,index):
        self.fr[self.enabled].grid_remove()
        self.fr[index].grid(row = 0, column = 2, rowspan=10)
        self.but[self.enabled].config(bg="white")
        self.but[index].config(bg="yellow")
        self.enabled = index
root=Tkinter.Tk()
note=button_note(root)
root.mainloop()

P.S. И вот зачем тут стирают пустые строки из кода…
4kpt_III
Практически верно. Преобразование толковое. Даже ошибки описывать не хочется

terabayt
но в функции изменяется переменная

И что Вас смутило? (Слово-подсказка: mutable).
terabayt
4kpt_III
И что Вас смутило?
то что числа в пайтоне immutable, а active это число
засунуть его в список? Вы считаете это решением?..
прошу показать Ваше решение.
4kpt_III
Все верно. Только не засунуть, а использовать вместо целого числа список или словарь (если управляющих параметров множество). Что тут Вас смутило? Неужели никогда в коде такого не видели?

Я же не написал, что в lambda нужно передавать именно число. Не люблю себя цитировать, но все же

4kpt_III
Тут два варианта. Либо ООП, либо явно передавать в lambda.

Я написал, что нужно что-то явно передавать в lambda…

P.S. В ангуляре, если я не ошибаюсь, также используется такой механизм. Чтобы не рисковать иногда применяют изменяемый объект.

P.S.S. Ну и если так настаиваете, то есть еще три варианта, при которых этот active вообще не нужен Индексировать там по-большому счету нечего-то.
terabayt
4kpt_III
Неужели никогда в коде такого не видели?
видел и для меня эт очень запутано
я не считаю это хорошим выходом
4kpt_III
Я же не написал, что в lambda нужно передавать именно число.
понял, вопросов больше нету

P.S. а вот если кто-то зарегистрирует на форуме 4kpt_IV (и 4kpt_IIII)? прост очень интересно )
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB