
在使用 Tkinter 进行图形界面开发时,采用面向对象编程(OOP)可以使代码更具可读性和模块化,但也会引入一些常见的问题。
1、问题背景
在学习 Python 的 Tkinter 和面向对象编程 (OOP) 时,遇到以下问题:
from Tkinter import Tk, Frame, Label
class Nexus(object):
def __init__(self, main_window):
self.nexus_frame = Frame(main_window)
self.nexus_frame.pack()
self.label = Label(main_window, text="Tkinter")
self.label.pack()
def main():
main_window = Tk()
nexus_app = Nexus(main_window)
main_window.wm_title("Hello World Window")
width = main_window.winfo_screenwidth()
height = main_window.winfo_screenheight()
main_window.wm_minsize(width=width-100, height=height-100)
main_window.mainloop()
if __name__ == "__main__":
main()在这个代码中,顶层窗口 (main_window) 是在 main() 函数中创建的,然后作为参数传递给 Nexus 类,在 Nexus 类中添加了一个框架 (Frame) 和一个标签 (Label) 到该框架中。然后在 main() 函数中设置了顶层窗口的大小,相对当前屏幕的大小。
问题是为什么在 main() 函数中创建顶层窗口?能不能在 Nexus 类的 __init__ 方法中创建顶层窗口?如果在 Nexus 类的 __init__ 方法中创建顶层窗口并启动 mainloop(),会有什么不同?
2、解决方案
2.1 解释问题
在 Tkinter 中,mainloop() 方法是一个无限循环,它会持续处理事件,直到窗口被关闭。一旦进入 Tk.mainloop,就不会执行任何其他代码。
如果在 Nexus 类的 __init__ 方法中创建顶层窗口并启动 mainloop(),那么 __init__ 方法就永远不会返回,这是意外的。如果程序员看到以下代码:
def main():
Nexus()
print('Hello world!')那么他会期望 print 语句被执行。通常情况下,我们不会期望创建类的实例会导致无限循环(因为事件循环是无限循环的)。
此外,如果在 Nexus 类的 __init__ 方法中创建顶层窗口并启动 mainloop(),那么就不可能创建多个 Nexus 实例,因为一旦创建一个 Nexus 实例,Tk.mainloop 就会接管。这也不是期望的结果:一个类是对象类型的描述,我们通常希望能够实例化多个这样的对象。
2.2 解决方案
因此,在处理 GUI 程序时,进入事件循环是最后要做的事情。设置可能涉及创建单个对象(如当前情况),也可能涉及创建多个对象(例如,复杂的 GUI 应用程序可能有两个或三个窗口)。
因为我们希望在两种情况下都能编写类似的代码,所以通常的做法是创建根窗口(Tk 对象)一次,然后将其作为引用传递给需要了解它的任何类。
在这段代码中,顶层窗口 (main_window) 在 main() 函数中创建,然后作为参数传递给 Nexus 类。在 Nexus 类中,使用 main_window 创建了一个框架 (Frame) 和一个标签 (Label)。然后在 main() 函数中设置了顶层窗口的大小,相对当前屏幕的大小。
如果想在 Nexus 类的 __init__ 方法中创建顶层窗口,可以这样做:
class Nexus(object):
def __init__(self):
self.main_window = Tk()
self.main_window.wm_title("Hello World Window")
self.nexus_frame = Frame(self.main_window)
self.nexus_frame.pack()
self.label = Label(self.main_window, text="Tkinter")
self.label.pack()但是,需要确保在 __init__ 方法的末尾调用 mainloop() 方法,以启动事件循环:
class Nexus(object):
def __init__(self):
self.main_window = Tk()
self.main_window.wm_title("Hello World Window")
self.nexus_frame = Frame(self.main_window)
self.nexus_frame.pack()
self.label = Label(self.main_window, text="Tkinter")
self.label.pack()
self.main_window.mainloop()这样,Nexus 类就可以在 __init__ 方法中创建顶层窗口并启动事件循环,而不会导致问题。
总结
tk.Frame 实现页面切换。grid 配合权重实现自适应布局。通过这些方法,可以解决 Tkinter 面向对象编程中的常见问题,使代码更加模块化、可维护。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。