简体   繁体   English

模块化更大的 tkinter 程序

[英]Modularizing larger tkinter program

I have a GUI that I'm designing using tkinter.我有一个使用 tkinter 设计的 GUI。 I have it built inside a class.我把它建在一个班级里。 The structure that I usually use is to create a frame and pack all my widgets into it.我通常使用的结构是创建一个框架并将我所有的小部件打包到其中。 Then when I need to show a different screen, I destroy that frame and call a function that creates a new parent frame and new widgets to pack into it.然后,当我需要显示不同的屏幕时,我会销毁该框架并调用一个函数来创建一个新的父框架和新的小部件来打包到其中。 Here's a simple example to clarify this structure.这里有一个简单的例子来阐明这个结构。

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()

I prefer this structure to Toplevel windows because I've had problems working with them in the past (windows dropping behind other open windows, focus issues, etc).我更喜欢这种结构而不是顶层窗口,因为我过去在使用它们时遇到了问题(窗口落在其他打开的窗口后面,焦点问题等)。 But I really miss how easy Toplevel windows make it to build modules, instead of having all the code in a single script.但我真的很怀念 Toplevel 窗口如何轻松地构建模块,而不是将所有代码都放在一个脚本中。 Is there a way to easily modularize a structure like this without using Toplevel?有没有一种方法可以在不使用 Toplevel 的情况下轻松地模块化这样的结构? It would be great for organization and readability.这对于组织和可读性来说会很棒。 I've tried taking the different 'screen creation' functions and putting them in modules, but I'm getting circular dependency issues.我尝试采用不同的“屏幕创建”功能并将它们放入模块中,但我遇到了循环依赖问题。

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模块.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()

When I click on the button that should take me to the frame built in the module, I get:当我点击应该带我到模块中内置框架的按钮时,我得到:

AttributeError: partially initialized module 'module' has no attribute 'a' (most likely due to a circular import) AttributeError: 部分初始化的模块“module”没有属性“a”(很可能是由于循环导入)

You can avoid the partially initialized module error due to the circular import by simply adding an if __name__ == '__main__': guard around the code near the end of the main script as shown below (which prevents the statements following it from executing when it's imported by module.py ).您可以通过简单地添加一个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 (no significant change) 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM