本文总结如何创建 Tkinter
多窗体。
Update: 2022 / 11 / 12
Python | GUI | Tkinter - 3. 多窗体
Tkinter 多窗体
组件
许多对象和子系统不喜欢接收来自多个不同线程的请求,并且在 GUI
工具包的情况下,专门需要仅使用主线程的情况并不少见。
Tkinter
设计为仅从主线程运行。即只需在主线程中运行所有 UI
代码,然后让编写者写入 Queue
对象。例如辅助线程将请求写入队列,主循环专门负责与 Tk
的所有直接交互。
为了解决这个问题,Python
架构总是将一个线程(主线程,如果必须的话)用于服务挑剔的对象或子系统。需要与所述子系统或对象交互的所有其他线程必须通过将请求排队到专用线程来获得它(如果某些请求需要结果,则可能在 返回队列
上等待结果)。这也是用于通用线程的非常完善的 Python
架构(在 Python in a Nutshell
中详细阐述了它,但这是另一个主题。
你是否有理由想要(或认为你需要)每个顶层窗口一个事件循环?单个事件循环能够处理数十个(如果不是数百或数千个)顶层窗口。而且,正如在另一个答案中所指出的那样,你不能在单独的线程中运行此事件循环。
通常来说,只需要使用一个事件循环,并让它在主线程中运行 1。
示例
1.
非组件
也可以不使用 Top level
组件来模拟一下多窗体切换,将所有的代码都写在一个模块内,简单的程序也可以采取这种方法 2。
比如,
- 把2个窗体写在2个函数里。先展示第1个窗体,通过内嵌函数判断是否满足要求,
- 如果满足要求,则关闭窗体1并随即开启第2个窗体;
- 如果不满足要求,则直接退出窗体1,窗体2也不会显示。
- 由一个主窗口切换到2个(或N个)窗体,同时也可以由这些窗口返回到主窗口来。
示例
1. 一个窗体一个函数
from tkinter import *
def one():
def ok():
if en1.get() == '123456':
root1.destroy() # close win 1
two() # enter win 2
root1 = Tk()
root1.title('win 1')
root1.geometry('300x150+888+444')
Label(root1, text='Please input your password.', bg='lightgreen').pack(fill=X)
en1 = Entry(root1)
en1.pack()
butone1 = Button(root1, text="Submit", command=ok)
# whether satisfy the condition or not
butone1.pack(pady=5)
root1.mainloop()
def two():
root2 = Tk()
root2.title('win 2')
root2.geometry('300x150+888+444')
Label(root2, text='This is win 2.', bg='lightblue').pack(fill=X)
root2.mainloop()
if __name__ == '__main__':
one()
运行时效果如下所示:
2. 一个主窗体切换多个二级窗口
from tkinter import *
def main(): # enter main
def goto(num):
root.destroy() # destroy main win
if num == 1:
one() # enter win 1
elif num == 2:
two() # enter win 2
root = Tk()
root.title('Main')
butmain1 = Button(root, text="Go into win 1", command=lambda: goto(1))
# enter win 1
butmain1.pack(pady=5)
butmain2 = Button(root, text="Go into win 2", command=lambda: goto(2))
# enter win 2
butmain2.pack(pady=5)
root.mainloop()
def one():
def gotomain():
root1.destroy() # close win 1
main() # enter main
root1 = Tk()
root1.geometry('300x150+888+444')
root1.title('win 1')
Label(root1, text='This is win 1.', bg='lightgreen').pack(fill=X)
butone1 = Button(root1, text="Back to main", command=gotomain)
butone1.pack(pady=10)
root1.mainloop()
def two():
def gotomain():
root2.destroy() # close win 2
main() # enter main
root2 = Tk()
root2.geometry('300x150+888+444')
root2.title('win 2')
Label(root2, text='This is win 2.', bg='lightblue').pack(fill=X)
buttwo1 = Button(root2, text="Back to main", command=gotomain)
buttwo1.pack(pady=10)
root2.mainloop()
if __name__ == '__main__':
main()
运行时效果如下所示: