2011-09-25 26 views
52

Ho creato i miei primi script con una piccola GUI su di essi, come i tutorial mi hanno mostrato, ma nessuno di loro si occupa di cosa fare per un programma più complesso.Passa da un fotogramma all'altro in tkinter

Se si dispone di qualcosa con un "menu di avvio", per la schermata di apertura e in seguito alla selezione dell'utente, si passa a una sezione diversa del programma e si ridisegna lo schermo in modo appropriato, qual è il modo elegante di farlo?

Una sola .destroy() la cornice del 'menu di avvio' e quindi la creazione di una nuova riempita con i widget per un'altra parte? E invertire questo processo quando premono il pulsante Indietro?

risposta

88

Un modo è quello di impilare i fotogrammi uno sopra l'altro, quindi è possibile sollevarli uno sopra l'altro nell'ordine di sovrapposizione. Quello in cima sarà quello visibile. Funziona meglio se tutti i fotogrammi hanno le stesse dimensioni, ma con un po 'di lavoro puoi farlo funzionare con cornici di qualsiasi dimensione.

Nota: per questo al lavoro, tutti i widget per una pagina deve avere quella pagina (es: self) o di un discendente come un genitore (o un master, a seconda della terminologia che preferite).

Ecco un po 'di un esempio inventato per mostrare il concetto generale:

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

start pagepage 1page 2

Se si trova il concetto di creazione di un'istanza in una classe di confusione, o se le pagine diverse necessità diversi argomenti durante la costruzione, puoi chiamare esplicitamente ogni classe separatamente. Il ciclo serve principalmente a illustrare il punto in cui ogni classe è identica.

Ad esempio, per creare le classi singolarmente è possibile rimuovere il loop (for F in (StartPage, ...) con questo:

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

Negli tempo le persone hanno chiesto altre domande utilizzando questo codice (o un tutorial online che copiato questo codice) come punto di partenza si potrebbe desiderare di leggere le risposte a queste domande:.

+2

Wow, grazie mille. Proprio come una domanda accademica piuttosto che una pratica, quante di queste pagine sono nascoste l'una sopra l'altra, di cui avresti bisogno prima che iniziasse a diventare lenta e insensibile? –

+2

Non lo so. Probabilmente migliaia.Sarebbe abbastanza facile da testare. –

+0

@BryanOakley ottima risposta, se ho una vista ad albero, per esempio, pageTwo e voglio aggiornarmi quando alcuni dati sono compilati nella pagina Uno come posso chiamare un metodo o una funzione nella pagina Due per aggiornare la vista ad albero. – diego

16

Ecco un'altra risposta semplice, ma senza l'utilizzo di classi.

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

Come possiamo mostrare l'etichetta, pulsante in grande. Sembra che la cornice abbia una larghezza e un'altezza ridotte. Anche dopo aver aumentato le dimensioni della finestra usando root.geometry() – velpandian

Problemi correlati