Python 在tkinter中的两个帧之间切换

Python 在tkinter中的两个帧之间切换,python,python-3.x,tkinter,frame,Python,Python 3.x,Tkinter,Frame,正如教程所示,我已经用一个漂亮的小GUI构建了最初的几个脚本,但是没有一个脚本能够解决如何处理更复杂的程序 如果您有一个“开始菜单”,用于打开屏幕,并且在用户选择后,您移动到程序的不同部分并适当地重新绘制屏幕,那么这样做的优雅方式是什么 是否只需.destroy()打开“开始菜单”框架,然后为另一部分创建一个充满小部件的新框架?当他们按下“后退”按钮时,可以反转此过程?一种方法是将帧堆叠在彼此的顶部,然后您可以简单地按照堆叠顺序将一帧提升到另一帧之上。顶部的那个将是可见的那个。如果所有帧的大小都

正如教程所示,我已经用一个漂亮的小GUI构建了最初的几个脚本,但是没有一个脚本能够解决如何处理更复杂的程序

如果您有一个“开始菜单”,用于打开屏幕,并且在用户选择后,您移动到程序的不同部分并适当地重新绘制屏幕,那么这样做的优雅方式是什么


是否只需
.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()
      
      

      <