Переключение между двумя кадрами в tkinter
Я построил свои первые несколько скриптов с приятным небольшим графическим интерфейсом на них, как показали учебники, но ни один из них не решает, что делать для более сложной программы.
Если у вас что-то с меню "Пуск", на экране открытия, и после выбора пользователя вы переходите к другой части программы, и соответствующим образом обновить экран, что это элегантный способ сделать это?
не только .destroy() рамочных меню "Пуск", а затем создать новый заполнены виджетами для другой части? И отменить этот процесс, когда они нажимают кнопку Назад?
3 ответов:
один из способов состоит в том, чтобы сложить кадры друг на друга, то вы можете просто поднять один над другим в порядке укладки. Сверху будет видна. Это работает лучше всего, если все кадры имеют одинаковый размер, но с небольшим работы, вы можете заставить его работать с любым размером рамы.
Примечание: чтобы это работало, все виджеты для страницы должны иметь эту страницу (т. е.:
self) или потомок как родитель (или мастер, в зависимости от терминологии вы предпочитать.)вот немного надуманный пример, чтобы показать вам общую концепцию:
import tkinter as tk # python 3 from tkinter import font as tkfont # python 3 #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")
со временем люди задавали другие вопросы, используя этот код (или онлайн учебник, который скопировал этот код) в качестве отправной точки. Вы можете прочитать ответы на эти вопросы:
- понимание родителя и контроллера в Tkinter __init__
- Tkinter! Понимание того, как переключаться кадры
- как получить переменные данные из класса
- вызов функций из кадра Tkinter в другой
- как получить доступ к переменным из разных классов в tkinter?
- как бы я сделал метод, который запускается каждый раз, когда кадр отображается в tkinter
- Tkinter Кадр Изменить Размер
- Tkinter код для страниц в отдельных файлах
- обновить кадр tkinter при нажатии кнопки
вот еще один простой ответ, но без использования классов.
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, уничтожить старый кадр, а затем заменить его на новый кадр.пока укладка рамы Брайана Оукли умное решение, оно держит каждый кадр активным сразу. Это имеет непреднамеренный побочный эффект, который позволяет пользователям выбирать виджеты из других кадров, нажав Tab.
я изменил ответ Брайана, чтобы уничтожить старую рамку перед ее заменой. В качестве дополнительного бонуса, это устраняет необходимость
containerобъект и позволяет использовать любые общиеFrameкласса.# 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()объяснение
switch_frame()работает, принимая любой объект класса, который реализуетFrame. Затем функция создает новый кадр для замены старого.
- удаляет старые
_frameесли он существует, то заменяет его новая рамка.- другие кадры добавлены с
.pack(), такие как menubars, не будут затронуты.- может использоваться с любым классом, который реализует
tkinter.Frame.- окно автоматически изменяется в соответствии с новым контентом
История Версий
v2.3 - Pack buttons and labels as they are initialized v2.2 - Initialize `_frame` as `None`. - Check if `_frame` is `None` before calling `.destroy()`. v2.1.1 - Remove type-hinting for backwards compatibility with Python 3.4. v2.1 - Add type-hinting for `frame_class`. v2.0 - Remove extraneous `container` frame. - Application now works with any generic `tkinter.frame` instance. - Remove `controller` argument from frame classes. - Frame switching is now done with `master.switch_frame()`. v1.6 - Check if frame attribute exists before destroying it. - Use `switch_frame()` to set first frame. v1.5 - Revert 'Initialize new `_frame` after old `_frame` is destroyed'. - Initializing the frame before calling `.destroy()` results in a smoother visual transition. v1.4 - Pack frames in `switch_frame()`. - Initialize new `_frame` after old `_frame` is destroyed. - Remove `new_frame` variable. v1.3 - Rename `parent` to `master` for consistency with base `Frame` class. v1.2 - Remove `main()` function. v1.1 - Rename `frame` to `_frame`. - Naming implies variable should be private. - Create new frame before destroying old frame. v1.0 - Initial version.






Comments