Форум сайта python.su
Здравствуйте.
При клике по Frame вызывается функция fn(). Можно ли замутить так, чтобы она вызывалась и при клике по объектам, расположенным на этой Frame? Ну кроме того, чтобы вручную прикручивать её к каждому объекту.
Офлайн
Если каждый объект реализован в виде класса, унаследованного от класса tkinter, то можно примерно так:
def fn(): .... f = Frame() for object in f.winfo_children(): object.bind("<Button-1>", lambda event: fn()) ....
from tkinter import * def fn(event): print("clicked", event) root = Tk() f1 = Frame(root) b1 = Button(f1, text='Button 1') b2 = Button(f1, text='Button 2') t1 = Text(f1) t1.pack() b1.pack() b2.pack() for child in f1.winfo_children(): child.bind("<1>", lambda event: fn(event)) f1.pack() root.mainloop()
Офлайн
Вот как-раз так ни в коем случае писать нельзя
def fn(): .... f = Frame() for object in f.winfo_children(): object.bind("<Button-1>", lambda event: fn()) ....
Отредактировано 4kpt_IV (Март 9, 2016 23:43:46)
Офлайн
4kpt_IVЦелью моего поста было всего лишь показать работу метода winfo_children(), а не предложение таким образом реализовывать код В первой же строчке моего поста написано про наследование классов вообще-то. Я подразумевал, что и контейнерный класс тоже отнаследован от соответствующего, то есть, как вы и написали, от Frame. Я предположил, что человек просто не знает про существование этого метода, а уж как именно он его задействует, оставил на его усмотрение. Однако, у вас я вижу только общие слова, но нет конкретики - как же именно переопределить метод bind()?
Вот как-раз так ни в коем случае писать нельзя
Офлайн
drevoborod
Однако, у вас я вижу только общие слова, но нет конкретики - как же именно переопределить метод bind()?
child.bind("<1>", lambda event: fn(event))
child.bind("<1>", fn)
Офлайн
Да, вы правы, надо было написать как следует, если уж решил полный пример писать. Разумеется, всё вами перечисленное мне известно, но до автоматизма не доведено пока, так что, когда пишу быстро, получается не очень красиво.
Но всё-таки целью моей было всего лишь продемонстрировать применения метода winfo_children. Когда я у вас спросил, как именно вы предлагаете реализовать переопределение bind, я имел в виду конкретный код. Будет ли в этом новом bind использоваться тот же самый winfo_children для обхода всех потомков или что-то другое?
Офлайн
Использовать желательно немного измененную внутреннюю реализацию winfo_children. Сразу нужно при получении дочерних виджетов вешать им bind. Плюс нужно строить это дело рекурсивно.
Офлайн
А вот про рекурсию я не подумал, полезное замечание.
Переписал пример более кошерно В таком виде класс MyFrame можно даже импортировать из модуля. В демонстрационном примере используются различные виджеты, встроенные в корневой контейнер на 1-2 уровня. Вместо winfo_children с рекурсией я воспользовался готовым решением - методом bind_all .
import tkinter class MyFrame(tkinter.Frame): def __init__(self, parent=None, **options): tkinter.Frame.__init__(self, master=parent, **options) def bind(self, sequence=None, func=None, add=None): tkinter.Frame.bind_all(self, sequence, func, add) def myfunc(event): print("clicked", event.widget._name) if __name__ == "__main__": root = tkinter.Tk() external_frame = MyFrame(root) tkinter.Button(external_frame, text='External Button 1').pack() tkinter.Button(external_frame, text='External Button 2').pack() internal_frame = tkinter.Frame(external_frame) internal_frame.pack() tkinter.Button(internal_frame, text='Internal button').pack() text1 = tkinter.Text(external_frame) checkbox1 = tkinter.Checkbutton(text="Check me") checkbox2 = tkinter.Checkbutton(text="Check me too") text1.window_create("end", window=checkbox1) text1.insert('end', ' some text ') text1.window_create('end', window=checkbox2) text1.pack() external_frame.bind("<Button-1>", myfunc) external_frame.pack() root.mainloop()
Отредактировано drevoborod (Март 10, 2016 22:08:03)
Офлайн
Напрасно использовали bind_all. Он немного не для того Создайте кнопку вне рамки и убедитесь в этом
И так уже не делается:
tkinter.Frame.__init__(self, master=parent, **options)
super().__init__(self, master=parent, **options)
Офлайн
В таком случае, мой класс будет выглядеть так:
class MyFrame(tkinter.Frame): def bind(self, sequence=None, func=None, add=None): for child in self.winfo_children(): child.bind(sequence, func, add) MyFrame.bind(child, sequence, func, add)
Отредактировано drevoborod (Март 10, 2016 23:24:41)
Офлайн