Una forma es apilar los marcos uno encima del otro, luego simplemente puede levantar uno encima del otro en el orden de apilamiento. El de arriba será el que esté visible. Esto funciona mejor si todos los marcos son del mismo tamaño, pero con un poco de trabajo puede hacer que funcione con marcos de cualquier tamaño.
Nota : para que esto funcione, todos los widgets de una página deben tener esa página (es decir:) self
o un descendiente como padre (o maestro, según la terminología que prefiera).
Aquí hay un pequeño ejemplo artificial para mostrarle el concepto general:
try:
import tkinter as tk
from tkinter import font as tkfont
except ImportError:
import Tkinter as tk
import tkFont as tkfont
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")
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
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()
Si encuentra confuso el concepto de crear una instancia en una clase, o si diferentes páginas necesitan diferentes argumentos durante la construcción, puede llamar explícitamente a cada clase por separado. El ciclo sirve principalmente para ilustrar el punto de que cada clase es idéntica.
Por ejemplo, para crear las clases individualmente puede eliminar el bucle ( for F in (StartPage, ...)
con esto:
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")
Con el tiempo, la gente ha hecho otras preguntas utilizando este código (o un tutorial en línea que copia este código) como punto de partida. Es posible que desee leer las respuestas a estas preguntas:
pack_forget
se puede usar si está usandopack
.Aquí hay otra respuesta simple, pero sin usar clases.
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()
fuente
Una forma de cambiar los marcos
tkinter
es destruir el marco antiguo y luego reemplazarlo por el nuevo.He modificado la respuesta de Bryan Oakley para destruir el marco anterior antes de reemplazarlo. Como ventaja adicional, esto elimina la necesidad de un
container
objeto y le permite usar cualquierFrame
clase genérica .# Multi-frame tkinter application v2.3 import tkinter as tk class SampleApp(tk.Tk): def __init__(self): tk.Tk.__init__(self) self._frame = None self.switch_frame(StartPage) def switch_frame(self, frame_class): """Destroys current frame and replaces it with a new one.""" new_frame = frame_class(self) if self._frame is not None: self._frame.destroy() self._frame = new_frame self._frame.pack() class StartPage(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) tk.Label(self, text="This is the start page").pack(side="top", fill="x", pady=10) tk.Button(self, text="Open page one", command=lambda: master.switch_frame(PageOne)).pack() tk.Button(self, text="Open page two", command=lambda: master.switch_frame(PageTwo)).pack() class PageOne(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) tk.Label(self, text="This is page one").pack(side="top", fill="x", pady=10) tk.Button(self, text="Return to start page", command=lambda: master.switch_frame(StartPage)).pack() class PageTwo(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) tk.Label(self, text="This is page two").pack(side="top", fill="x", pady=10) tk.Button(self, text="Return to start page", command=lambda: master.switch_frame(StartPage)).pack() if __name__ == "__main__": app = SampleApp() app.mainloop()
Explicación
switch_frame()
funciona aceptando cualquier objeto Class que implementeFrame
. Luego, la función crea un nuevo marco para reemplazar el anterior._frame
si existe, luego lo reemplaza con el nuevo marco..pack()
, como las barras de menú, no se verán afectados.tkinter.Frame
.Historial de versiones
fuente
self
).switch_frame()
podría ser un poco engañoso. ¿Debería cambiarle el nombre areplace_frame()
?