Python 在tkinter中的两个帧之间切换
正如教程所示,我已经用一个漂亮的小GUI构建了最初的几个脚本,但是没有一个脚本能够解决如何处理更复杂的程序 如果您有一个“开始菜单”,用于打开屏幕,并且在用户选择后,您移动到程序的不同部分并适当地重新绘制屏幕,那么这样做的优雅方式是什么Python 在tkinter中的两个帧之间切换,python,python-3.x,tkinter,frame,Python,Python 3.x,Tkinter,Frame,正如教程所示,我已经用一个漂亮的小GUI构建了最初的几个脚本,但是没有一个脚本能够解决如何处理更复杂的程序 如果您有一个“开始菜单”,用于打开屏幕,并且在用户选择后,您移动到程序的不同部分并适当地重新绘制屏幕,那么这样做的优雅方式是什么 是否只需.destroy()打开“开始菜单”框架,然后为另一部分创建一个充满小部件的新框架?当他们按下“后退”按钮时,可以反转此过程?一种方法是将帧堆叠在彼此的顶部,然后您可以简单地按照堆叠顺序将一帧提升到另一帧之上。顶部的那个将是可见的那个。如果所有帧的大小都
是否只需
.destroy()
打开“开始菜单”框架,然后为另一部分创建一个充满小部件的新框架?当他们按下“后退”按钮时,可以反转此过程?一种方法是将帧堆叠在彼此的顶部,然后您可以简单地按照堆叠顺序将一帧提升到另一帧之上。顶部的那个将是可见的那个。如果所有帧的大小都相同,那么这种方法效果最好,但只需稍加努力,您就可以将其用于任何大小的帧
注意:要使其正常工作,页面的所有小部件必须具有该页面(即:self
)或子代作为父级(或主级,取决于您喜欢的术语)
下面是一个精心设计的示例,向您展示一般概念:
try:
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
except ImportError:
import Tkinter as tk # python 2
import tkFont as tkfont # python 2
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page Two",
command=lambda: controller.show_frame("PageTwo"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
如果您发现在类中创建实例的概念令人困惑,或者如果不同的页面在构造过程中需要不同的参数,则可以分别显式调用每个类。循环主要用于说明每个类都是相同的这一点
例如,要单独创建类,可以使用以下方法删除循环(For F in(StartPage,…)
:
self.frames["StartPage"] = StartPage(parent=container, controller=self)
self.frames["PageOne"] = PageOne(parent=container, controller=self)
self.frames["PageTwo"] = PageTwo(parent=container, controller=self)
self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
self.frames["PageOne"].grid(row=0, column=0, sticky="nsew")
self.frames["PageTwo"].grid(row=0, column=0, sticky="nsew")
随着时间的推移,人们会以此代码(或复制此代码的在线教程)为起点提出其他问题。您可能希望阅读这些问题的答案:
- 这里是另一个简单的答案,但不使用类
from tkinter import *
def raise_frame(frame):
frame.tkraise()
root = Tk()
f1 = Frame(root)
f2 = Frame(root)
f3 = Frame(root)
f4 = Frame(root)
for frame in (f1, f2, f3, f4):
frame.grid(row=0, column=0, sticky='news')
Button(f1, text='Go to frame 2', command=lambda:raise_frame(f2)).pack()
Label(f1, text='FRAME 1').pack()
Label(f2, text='FRAME 2').pack()
Button(f2, text='Go to frame 3', command=lambda:raise_frame(f3)).pack()
Label(f3, text='FRAME 3').pack(side='left')
Button(f3, text='Go to frame 4', command=lambda:raise_frame(f4)).pack(side='left')
Label(f4, text='FRAME 4').pack()
Button(f4, text='Goto to frame 1', command=lambda:raise_frame(f1)).pack()
raise_frame(f1)
root.mainloop()
注意:,下面的答案可能会因为重复破坏和重新创建帧而导致错误。但是,我自己还没有测试来验证这一点
在tkinter
中切换帧的一种方法是销毁旧帧,然后用新帧替换它
我修改了answer,在替换旧框架之前将其销毁。作为额外的好处,这消除了对容器
对象的需要,并允许您使用任何通用框架
类
#多帧tkinter应用v2.3
将tkinter作为tk导入
类SampleApp(tk.tk):
定义初始化(自):
tk.tk.\uuuuu初始化(self)
self.\u frame=None
自交换框架(起始页)
def开关_框架(自身,框架类):
“”“销毁当前帧并用新帧替换它。”“”
新框架=框架类(自身)
如果self.\u frame不是None:
self.\u frame.destroy()
self.\u frame=新的\u frame
self.\u frame.pack()
类起始页(传统框架):
定义初始(自我,主):
tk.Frame.\uuuuu init\uuuuuuu(自,主)
标签(self,text=“这是起始页”).pack(side=“top”,fill=“x”,pady=10)
按钮(self,text=“打开第一页”,
command=lambda:master.switch_frame(PageOne)).pack()
按钮(self,text=“打开第二页”,
command=lambda:master.switch_frame(第二页)).pack()
类别第一页(传统框架):
定义初始(自我,主):
tk.Frame.\uuuuu init\uuuuuuu(自,主)
标签(self,text=“这是第一页”).pack(side=“top”,fill=“x”,pady=10)
tk.按钮(self,text=“返回起始页”,
command=lambda:master.switch_frame(起始页)).pack()
第二类(传统框架):
定义初始(自我,主):
tk.Frame.\uuuuu init\uuuuuuu(自,主)
标签(self,text=“这是第二页”).pack(side=“top”,fill=“x”,pady=10)
tk.按钮(self,text=“返回起始页”,
command=lambda:master.switch_frame(起始页)).pack()
如果名称=“\uuuuu main\uuuuuuuu”:
app=SampleApp()
app.mainloop()
解释
switch\u frame()
通过接受实现的任何类对象来工作。然后该函数创建一个新的帧来替换旧的帧
- 删除旧帧(如果存在),然后用新帧替换
- 使用
添加的其他帧(如菜单栏)将不受影响.pack()
- 可以与实现
的任何类一起使用tkinter.Frame
- 窗口自动调整大小以适应新内容
v2.3
-在按钮和标签初始化时进行打包
v2.2
-将“U帧”初始化为“无”。
-在调用“.destroy()”之前,检查“\u frame”是否为“None”。
v2.1.1
-删除类型提示以向后兼容Python 3.4。
v2.1
-为“frame\u class”添加类型提示。
v2.0
-拆下无关的“容器”框架。
-应用程序现在可以与任何通用的'tkinter.frame'实例一起使用。
-从框架类中删除'controller'参数。
-帧切换现在通过“master.switch_Frame()”完成。
v1.6
-在销毁帧属性之前,请检查其是否存在。
-使用“switch_frame()”设置第一帧。
v1.5
-在旧的``框架'被销毁后恢复'初始化新的``框架'。
-在调用“.destroy()”结果之前初始化帧
以更平滑的视觉过渡。
v1.4
-将帧打包到“switch_frame()”。
-在旧的`\u frame`被销毁后初始化新的`\u frame`。
-删除'new_frame'变量。
v1.3
-将'parent'重命名为'master',以与基'Frame'类保持一致。
v1.2
-删除`main()`函数。
v1.1
-将“frame”重命名为“u frame”。
-命名意味着变量应该是私有的。
-在销毁旧帧之前创建新帧。
v1.0
-初始版本。
如果您使用的是pack
几何体管理器,则可能更直观的解决方案是使用pack\u-forget
方法隐藏/取消隐藏帧
这里有一个简单的例子
import tkinter as tk
class App:
def __init__(self, root=None):
self.root = root
self.frame = tk.Frame(self.root)
self.frame.pack()
tk.Label(self.frame, text='Main page').pack()
tk.Button(self.frame, text='Go to Page 1',
command=self.make_page_1).pack()
self.page_1 = Page_1(master=self.root, app=self)
def main_page(self):
self.frame.pack()
def make_page_1(self):
self.frame.pack_forget()
self.page_1.start_page()
class Page_1:
def __init__(self, master=None, app=None):
self.master = master
self.app = app
self.frame = tk.Frame(self.master)
tk.Label(self.frame, text='Page 1').pack()
tk.Button(self.frame, text='Go back', command=self.go_back).pack()
def start_page(self):
self.frame.pack()
def go_back(self):
self.frame.pack_forget()
self.app.main_page()
if __name__ == '__main__':
root = tk.Tk()
app = App(root)
root.mainloop()
<