Как в Python & tkinter при использовании MVC создать главное окно программы?

Пытаюсь реализовать шаблон MVC для приложения по примеру

https://github.com/li360/tkinter-mvc

В классе, отвечающим за создание главного окна приложения не знаю какие параметры использовать, - не отображаются элементы окна.

В примере 2 окна обмениваются данными, поэтому у них родительский класс выбран Toplevel. Но Toplevel не позволяет использовать вложенные элементы, такие как меню, ttk.Notebook и пр. и его рекомендуется использовать для диалоговых окон.

Как я понимаю, что происходит:

В main.py создается объект контроллера, ему передается ссылка на главное окно приложения, созданное с помощью root = Tk() => app = Controller(root).
В сонтроллере MainController.py создается объект окна self.view_main_window = ViewMainWindow(root) которому, в свою очередь, передается ссылка на главное окно приложения уже из класса контроллера.
MainView.py получает ссылку в конструкторе def init(self, parent), переименовывает self.master = parent. Дальше виджеты используют ее для определения своей принадлежности.
Это в теории, на практике, - после запуска окна нет, но и сообщений об ошибках тоже нет.

main.py
from tkinter import *
from controllers.MainController import Controller

if __name__ == '__main__':
    root = Tk()
    root.title("PyDOE-tk")
    root.withdraw()
    app = Controller(root)
    root.mainloop()


controllers/MainController.py
from models.MainModel import Model
from views.MainView import ViewMainWindow

class Controller:
    def __init__(self, root):
        self.model = Model()
        self.view_main_window = ViewMainWindow(root) 


views/MainView.py
from tkinter import *

class ViewMainWindow(Frame):
    def __init__(self, parent):
        Frame.__init__(self, parent)
        self.master = parent                    
        self.frame = Frame()
        self.frame.pack()
        self.button = Button(self.frame, text="myButton")
        self.button.pack(side=BOTTOM)
        self.name = Label(self.frame, text='Label')
        self.name.pack()


Если выбрать родительским классом Toplevel (как в примере на github), то окно показывается, но пустое:

class ViewMainWindow(Toplevel):
    def __init__(self, parent):
        Toplevel.__init__(self, parent)
        self.master = parent
        self.protocol('WM_DELETE_WINDOW', self.master.destroy)                    
        self.frame = Frame()
        self.frame.pack()
        self.button = Button(self.frame, text="myButton")
        self.button.pack(side=BOTTOM)
        self.name = Label(self.frame, text='Label')
        self.name.pack()


PS.
Если сделать файл исполняемым, как в примере ниже, то все работает. Отображается окно с кнопкой и текстом.
Потому и вопрос: какие параметры нужно передать из файла точки запуска через контроллер, что бы окно появилось с содержимым.


from tkinter import *
class ViewMainWindow:
    def __init__(self, parent):        
        self.master = parent        
        self.frame = Frame()
        self.frame.pack()
        self.button = Button(self.frame, text="myButton")
        self.button.pack(side=BOTTOM)
        self.name = Label(self.frame, text='Label')
        self.name.pack()
        self.master.mainloop()

root = Tk()
ViewMainWindow(root)


PS 2: Думал, что как то ссылка на главное окно не передается, ввел строку

print('type of root: ', type(parent), id(parent))
в main, контроллер и представление, оказалось, что ссылка на главное окно передается одна и та же:

type of root from main:  <class 'tkinter.Tk'> 2774823903920
type of root from controller:  <class 'tkinter.Tk'> 2774823903920
type of root from view:  <class 'tkinter.Tk'> 2774823903920
  • Вопрос задан
  • 1123 просмотра
Решения вопроса 1
budda
@budda Автор вопроса
Разобрался.

В примере на github показано взаимодействие двух окон, что несколько специфично, обычно большая часть действий выполняется в главном окне программы. Но поскольку там так задумано (в одном окне две кнопки, изменяющие значение лейбла в другом окне) для реализации независимых окон автору пришлось использовать окна Toplevel. Вот немного о них:

Марк Лутц Программирование на Python том I: Обычно окна Toplevel используются для реализации многооконных интерфейсов, а также модальных и немодальных диалогов. Они сохраняются до тех пор, пока не будут явно закрыты или пока создавшее их приложение не завершит работу.


Сколько я не пробовал менять параметры передачи ссылки на главное окно ничего не получалось, пока я не обратил внимание на метод root.withdraw() в файле main.py. Не смотря на название, оказалось, что он срывает окно:

withdraw() Removes the window from the screen (without destroying it). To redraw the window, use deiconify. When the window has been withdrawn, the state method returns “withdrawn”.


Но в примере он нужен, что бы скрыть пустое нефункциональное окно root, которое заменяют два независимых окна Toplevel. В моем случае - приложение будет однооконное, поэтому если убрать этот метод, то все сразу начинает работать.

Рабочий файл main.py выглядит так:

main.py
from tkinter import *
from controllers.MainController import Controller

if __name__ == '__main__':
    root = Tk()
    root.title("PyDOE-tk")    
    app = Controller(root)
    root.mainloop()
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы