Объектно-ориентированный 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()
Другие вопросы по тегам