Jednym ze sposobów jest układanie ramek jedna na drugiej, a następnie można po prostu unieść jedną nad drugą w kolejności układania. Ten na górze będzie tym, który jest widoczny. Działa to najlepiej, jeśli wszystkie ramki mają ten sam rozmiar, ale przy odrobinie pracy można sprawić, że będzie działać z ramkami o dowolnym rozmiarze.
Uwaga : aby to zadziałało, wszystkie widżety dla strony muszą mieć tę stronę (tj .:) self
lub element podrzędny jako element nadrzędny (lub wzorzec, w zależności od preferowanej terminologii).
Oto trochę wymyślony przykład, aby pokazać ogólną koncepcję:
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()
Jeśli koncepcja tworzenia instancji w klasie jest myląca lub jeśli różne strony wymagają różnych argumentów podczas konstruowania, możesz jawnie wywołać każdą klasę osobno. Pętla służy głównie do zilustrowania faktu, że każda klasa jest identyczna.
Na przykład, aby utworzyć klasy indywidualnie, możesz usunąć pętlę (za for F in (StartPage, ...)
pomocą tego:
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")
Z biegiem czasu ludzie zadawali inne pytania, używając tego kodu (lub samouczka online, który skopiował ten kod) jako punktu wyjścia. Możesz przeczytać odpowiedzi na następujące pytania:
pack_forget
może być używany, jeśli używaszpack
.Oto kolejna prosta odpowiedź, ale bez użycia klas.
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()
źródło
Jednym ze sposobów przełączania ramek
tkinter
jest zniszczenie starej ramki, a następnie zastąpienie jej nową ramką.Zmodyfikowałem odpowiedź Bryana Oakleya, aby zniszczyć starą ramę przed jej wymianą. Jako dodatkowy bonus eliminuje to potrzebę posiadania
container
obiektu i pozwala na użycie dowolnejFrame
klasy ogólnej .# 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()
Wyjaśnienie
switch_frame()
działa poprzez akceptowanie dowolnego obiektu klasy, który implementujeFrame
. Następnie funkcja tworzy nową ramkę, aby zastąpić starą._frame
ramkę, jeśli istnieje, a następnie zastępuje ją nową ramką..pack()
, takie jak paski menu, pozostaną niezmienione.tkinter.Frame
.Historia wersji
źródło
self
).switch_frame()
może być nieco myląca. Czy powinienem zmienić jego nazwę nareplace_frame()
?