Модуляризация большей программы tkinter - PullRequest
0 голосов
/ 30 января 2020

У меня есть GUI, который я проектирую, используя tkinter. Я построил это внутри класса. Структура, которую я обычно использую, состоит в том, чтобы создать рамку и упаковать в нее все мои виджеты. Затем, когда мне нужно показать другой экран, я уничтожаю этот кадр и вызываю функцию, которая создает новый родительский кадр и новые виджеты для упаковки в него. Вот простой пример, поясняющий эту структуру.

import tkinter as tk

class Window():
    def __init__(self, master):
        self.master = master
        self.master.geometry('300x300')
        frame = tk.Frame(self.master)
        frame.pack()
        self.main(frame)

    def goto(self, destination, frame):
        frame.destroy()
        frame = tk.Frame(self.master)
        frame.pack()
        goto = {
            'main': self.main,
            'a': self.a,
            'b': self.b
        }
        goto[destination](frame)

    def main(self, frame):
        tk.Label(frame, text='Main').pack()
        tk.Button(frame, text='Goto A', command=lambda: self.goto('a', frame)).pack()
        tk.Button(frame, text='Goto B', command=lambda: self.goto('b', frame)).pack()

    def a(self, frame):
        tk.Label(frame, text='A').pack()
        tk.Button(frame, text='Back to Main', command=lambda: self.goto('main', frame)).pack()

    def b(self, frame):
        tk.Label(frame, text='B').pack()
        tk.Button(frame, text='Back to Main', command=lambda: self.goto('main', frame)).pack()

root = tk.Tk()
Window(root)
root.mainloop()

Я предпочитаю эту структуру Toplevel windows, потому что у меня были проблемы с ними в прошлом (windows отстает от других открытых windows вопросы фокуса и др. c). Но я очень скучаю по тому, как легко Toplevel windows позволяет создавать модули вместо того, чтобы иметь весь код в одном скрипте. Есть ли способ легко модульной структуры, как это без использования Toplevel? Это было бы здорово для организации и читабельности. Я пытался взять разные функции «создания экрана» и поместить их в модули, но у меня возникают проблемы с циклической зависимостью.

main.py

import tkinter as tk
import module

class Window():
    def __init__(self, master):
        self.master = master
        self.master.geometry('300x300')
        frame = tk.Frame(self.master)
        frame.pack()
        self.main(frame)

    def goto(self, destination, frame):
        frame.destroy()
        frame = tk.Frame(self.master)
        frame.pack()
        goto = {
            'main': self.main,
            'a': module.a,
        }
        goto[destination](frame)

    def main(self, frame):
        tk.Label(frame, text='Main').pack()
        tk.Button(frame, text='Goto A', command=lambda: self.goto('a', frame)).pack()

root = tk.Tk()
window = Window(root)
root.mainloop()

module.py

import tkinter as tk
import main

def a(frame):
    tk.Label(frame, text='A').pack()
    tk.Button(frame, text='Back to Main', command=lambda: main.window.goto('main', frame)).pack()

Когда я нажимаю кнопку, которая приведет меня к рамке, встроенной в модуль, я получаю:

AttributeError: частично инициализированный модуль 'module' не имеет атрибута 'a '(скорее всего из-за кругового импорта)

1 Ответ

1 голос
/ 31 января 2020

Вы можете избежать частично инициализированной ошибки модуля из-за циклического импорта, просто добавив ограждение if __name__ == '__main__': вокруг кода в конце основного сценария, как показано ниже (что предотвращает выполнение следующих за ним операторов при его импорте module.py).

main.py

import tkinter as tk
import module

class Window():
    def __init__(self, master):
        self.master = master
        self.master.geometry('300x300')
        frame = tk.Frame(self.master)
        frame.pack()
        self.main(frame)

    def goto(self, destination, frame):
        frame.destroy()
        frame = tk.Frame(self.master)
        frame.pack()
        goto = {
            'main': self.main,
            'a': module.a,
        }
        goto[destination](frame)

    def main(self, frame):
        tk.Label(frame, text='Main').pack()
        tk.Button(frame, text='Goto A', command=lambda: self.goto('a', frame)).pack()


if __name__ == '__main__':  # ADDED
    root = tk.Tk()
    window = Window(root)
    root.mainloop()

module.py (без существенных изменений)

import tkinter as tk
import main


def a(frame):
    tk.Label(frame, text='A').pack()
    tk.Button(frame, text='Back to Main',
              command=lambda: main.window.goto('main', frame)).pack()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...