ventanas texto tablas gui for example espaƱol entry cuadro botones python python-3.x tkinter frame

texto - tkinter python 3



Cambiar entre dos cuadros en tkinter (3)

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()

He creado mis primeros guiones con una pequeña GUI, como me han mostrado los tutoriales, pero ninguno aborda qué hacer para un programa más complejo.

Si tiene algo con un "menú de inicio", para su pantalla de inicio, y luego de la selección del usuario, se mueve a una sección diferente del programa y vuelve a dibujar la pantalla de manera apropiada, ¿cuál es la forma elegante de hacerlo?

¿Uno solo .destroy() el cuadro de "menú de inicio" y luego crea uno nuevo con los widgets para otra parte? ¿Y revertir este proceso cuando presionan el botón Atrás?


Una forma es apilar los cuadros uno encima del otro, luego simplemente puede subir uno encima del otro en el orden de apilamiento. El que está en la parte superior será el que esté visible. Esto funciona mejor si todos los marcos son del mismo tamaño, pero con un poco de trabajo puede lograr 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, dependiendo de la terminología que prefiera).

Aquí hay un pequeño ejemplo para mostrarle el concepto general:

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()

Si considera que el concepto de crear instancia en una clase es confuso, o si las diferentes páginas necesitan argumentos diferentes durante la construcción, puede llamar explícitamente a cada clase por separado. El ciclo sirve principalmente para ilustrar el punto en que cada clase es idéntica.

Por ejemplo, para crear las clases individualmente, puede eliminar el ciclo ( 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, las personas han formulado otras preguntas utilizando este código (o un tutorial en línea que copió este código) como punto de partida. Es posible que desee leer las respuestas a estas preguntas:

  • Comprender padre y controlador en Tkinter __init__
  • ¡Tkinter! Comprender cómo cambiar marcos
  • Cómo obtener datos variables de una clase
  • Llamar funciones de un Marco Tkinter a otro
  • Cómo acceder a variables de diferentes clases en tkinter python 3
  • ¿Cómo crearía un método que se ejecuta cada vez que se muestra un marco en tkinter?
  • Tkinter Frame Resize
  • Py2.7: Tkinter tiene código para páginas en archivos separados

Para cambiar fotogramas en tkinter , destruya el fotograma antiguo y luego reemplácelo con su nuevo fotograma.

Mientras que el apilamiento de marcos de Bryan Oakley es una solución inteligente, mantiene todos los cuadros activos a la vez. Esto tiene un efecto secundario no deseado que permite a los usuarios seleccionar widgets de otros marcos presionando Tab .

He modificado la respuesta de Bryan para reemplazar show_frame() con switch_frame() , que destruye el antiguo marco antes de reemplazarlo. Esto elimina la necesidad de un objeto container y le permite usar cualquier clase Frame genérica.

# Multi-frame tkinter application v2.2 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) start_label = tk.Label(self, text="This is the start page") page_1_button = tk.Button(self, text="Open page one", command=lambda: master.switch_frame(PageOne)) page_2_button = tk.Button(self, text="Open page two", command=lambda: master.switch_frame(PageTwo)) start_label.pack(side="top", fill="x", pady=10) page_1_button.pack() page_2_button.pack() class PageOne(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) page_1_label = tk.Label(self, text="This is page one") start_button = tk.Button(self, text="Return to start page", command=lambda: master.switch_frame(StartPage)) page_1_label.pack(side="top", fill="x", pady=10) start_button.pack() class PageTwo(tk.Frame): def __init__(self, master): tk.Frame.__init__(self, master) page_2_label = tk.Label(self, text="This is page two") start_button = tk.Button(self, text="Return to start page", command=lambda: master.switch_frame(StartPage)) page_2_label.pack(side="top", fill="x", pady=10) start_button.pack() if __name__ == "__main__": app = SampleApp() app.mainloop()

Explicación

switch_frame() funciona aceptando cualquier objeto Class que implemente Frame . La función luego crea un nuevo marco para reemplazar el anterior.

  • Elimina _frame si existe, luego lo reemplaza con el nuevo fotograma.
  • Otros marcos agregados con .pack() , como menubars, no se verán afectados.
  • Se puede usar con cualquier clase que implemente tkinter.Frame .
  • La ventana cambia el tamaño automáticamente para adaptarse a contenido nuevo

Historial de versiones

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.