Объектно-ориентированный Tkinter, лучший способ взаимодействия между виджетами в графическом интерфейсе с множеством фреймов
Я пытаюсь выяснить, как лучше всего общаться между различными виджетами, где виджеты - это пользовательские классы, наследуемые от виджетов tkinter, и у меня есть несколько фреймов (чтобы помочь с управлением макетом). Рассмотрим, например, следующий простой графический интерфейс (написанный для python 3, замените tkinter на Tkinter для python 2):
from tkinter import Frame,Button,Tk
class GUI(Frame):
def __init__(self, root):
Frame.__init__(self,root)
self.upper_frame=Frame(root)
self.upper_frame.pack()
self.lower_frame=Frame(root)
self.lower_frame.pack()
self.upper_btn1 = Button(self.upper_frame, text="upper button 1")
self.upper_btn2 = Button(self.upper_frame, text="upper button 2")
self.upper_btn1.grid(row=0,column=0)
self.upper_btn2.grid(row=0,column=1)
self.lower_btn = CustomButton(self.lower_frame, "lower button 3")
self.lower_btn.pack()
class CustomButton(Button):
def __init__(self,master,text):
Button.__init__(self,master,text=text)
self.configure(command=self.onClick)
def onClick(self):
print("here I want to change the text of upper button 1")
root = Tk()
my_gui = GUI(root)
root.mainloop()
Причина, по которой я помещаю их в разные фреймы, заключается в том, что я хочу использовать разные менеджеры компоновки в двух разных фреймах для создания более сложной компоновки. Тем не менее, я хочу команду в lower_btn
изменить свойства, например, upper_btn1
,
Тем не менее, я не могу сразу получить доступ upper_btn1
из экземпляра lower_btn
индивидуального класса CustomButton
, Родитель lower_btn
является frame2
и frame2
parent - это root (не экземпляр GUI). Если я поменяю родителя lower_btn
к экземпляру GUI, т.е.
self.lower_btn = CustomButton(self, "lower button")
он не будет правильно размещен при использовании pack()
, Если я поменяю родителя frame1/frame2
к экземпляру GUI, т.е.
self.upper_frame=Frame(self)
self.upper_frame.pack()
self.lower_frame=Frame(self)
self.lower_frame.pack()
Я мог бы в принципе получить доступ к upper_btn1
от lower_btn
от self.master.master.upper_btn1
НО тогда frame1/frame2
неправильно размещены с помощью pack()
(это я не понимаю почему). Конечно, я могу передать экземпляр GUI как отдельную переменную поверх мастера, чтобы CustomButton
то есть что-то вроде
class CustomButton(Button):
def __init__(self,master,window,text):
Button.__init__(self,master,text=text)
self.window=window
self.configure(command=self.onClick)
def onClick(self):
self.window.upper_btn1.configure(text="new text")
а затем изменить конструкцию lower_btn
в
self.lower_btn = CustomButton(self.lower_frame,self, "lower button 3")
но это ли "правильный" способ сделать это?
Итак, каков наилучший способ реорганизации этого графического интерфейса? Должен ли я передавать GUI как отдельную переменную поверх аргумента master/parent? Должен ли я изменить основной / родительский элемент кнопок и / или рамок (и как-то решить проблемы с управлением макетом)? Или я должен сделать команды кнопок как методы экземпляра GUI, чтобы они могли взаимодействовать с виджетами в этом GUI, хотя на самом деле это не похоже на объектно-ориентированное программирование? Я не могу найти работающий объектно-ориентированный дизайн, который кажется "правильным". Кроме того, объяснение, почему pack()
не работает для frame1/frame2
если я сделаю экземпляр GUI (self
) мастер, также был бы оценен, поскольку это был бы мой интуитивный, наиболее объектно-ориентированный подход.
Редактировать: Возможно, лучший способ - вообще не использовать фреймы внутри фреймов, а использовать только grid(), а затем использовать colspan/rowspan, чтобы обеспечить более гибкое управление компоновкой.
0 ответов
Год спустя, но: Один из способов связи между виджетами - создать экземпляр какого-то объекта центра управления, который получает информацию о состоянии ваших виджетов, а затем заставляет другие виджеты действовать на основе этой информации. Эта функция "менеджера" не зависит от макета ваших виджетов.
Вот реализация, адаптированная к вашему примеру. Идея состоит в том, чтобы добавить.manager
атрибута нижней кнопки и уведомлять этого менеджера при нажатии. ВGUI
класс остается без изменений.
from tkinter import Frame,Button,Tk
class Manager(object):
def __init__(self, gui):
self.gui = gui
self.gui.lower_btn.manager = self
def onClick(self):
self.gui.upper_btn2.configure(text="changed text")
class GUI(Frame):
def __init__(self, root):
Frame.__init__(self,root)
self.upper_frame=Frame(root)
self.upper_frame.pack()
self.lower_frame=Frame(root)
self.lower_frame.pack()
self.upper_btn1 = Button(self.upper_frame, text="upper button 1")
self.upper_btn2 = Button(self.upper_frame, text="upper button 2")
self.upper_btn1.grid(row=0,column=0)
self.upper_btn2.grid(row=0,column=1)
self.lower_btn = CustomButton(self.lower_frame, "lower button 3")
self.lower_btn.pack()
class CustomButton(Button):
def __init__(self,master,text):
Button.__init__(self,master,text=text)
self.configure(command=self.onClick)
self.manager = None
def onClick(self):
if self.manager:
self.manager.onClick()
else:
print("here I want to change the text of upper button 1")
root = Tk()
my_gui = GUI(root)
Manager(my_gui)
root.mainloop()