33

I have quite a simple question here. In Tkinter (python), I was wondering who to use a button to go to different pages of my application, e.g a register page, and a login page. I am aware that GUI does not have 'pages' like websites do, I've seen a few different ways, but what is the best way to make links to different pages?

MendelG
  • 14,885
  • 4
  • 25
  • 52
Caspar Wylie
  • 2,818
  • 3
  • 18
  • 32

3 Answers3

54

Make each page a frame. Then, all your buttons need to do is hide whatever is visible, then make the desired frame visible.

A simple method to do this is to stack the frames on top of each other (this is one time when place makes sense) and then ,lift() the frame you want to be visible. This technique works best when all pages are the same size; in fact, it requires that you explicitly set the size of containing frame.

The following is a contrived example. This isn't the only way to solve the problem, just proof that it's not a particularly hard problem to solve:

import Tkinter as tk

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 1")
       label.pack(side="top", fill="both", expand=True)

class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 2")
       label.pack(side="top", fill="both", expand=True)

class Page3(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 3")
       label.pack(side="top", fill="both", expand=True)

class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)
        p3 = Page3(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p3.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        b1 = tk.Button(buttonframe, text="Page 1", command=p1.show)
        b2 = tk.Button(buttonframe, text="Page 2", command=p2.show)
        b3 = tk.Button(buttonframe, text="Page 3", command=p3.show)

        b1.pack(side="left")
        b2.pack(side="left")
        b3.pack(side="left")

        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • than you so much, exactly what i was after! – Caspar Wylie Feb 12 '13 at 09:06
  • @CasparWylie: All this example means is that this whole example is one block of text. You can divide it into as many files as you want -- that has nothing to do with the solution. Each "page" could easily be its own module. – Bryan Oakley Feb 12 '13 at 12:04
  • @BryanOakley, wouldn't it be better to use notebook for things like this? http://www.tkdocs.com/tutorial/complex.html#notebook – user3885927 Apr 15 '16 at 20:42
  • 3
    @user3885927: as with most usability questions, "that depends". This question wasn't about what's best, but simply how to switch between pages. You could use a notebook, yes, or you can use this technique to create your own custom notebook. For example, if you had 100 pages, you could create a notebook that uses a listbox for the list of pages, rather than try to squeeze a bunch of tabs across the top of the widget. – Bryan Oakley Apr 15 '16 at 20:45
  • How do I pass value of a variable from a function in MainView() to Page2()? – user1175126 Dec 08 '17 at 12:50
  • @BryanOakley Hi, is there a way of doing this (creating multiple pages) without using classes, only functions? – Aleksandar Beat Jun 03 '18 at 22:34
  • 1
    @AleksandarBeat: yes, of course. It might be a bit more cumbersome, but it's all just code. – Bryan Oakley Jun 03 '18 at 23:06
  • @BryanOakley can you maybe post an example code, I have looked everywhere but I didn't find anything. You can answer here, on this question: [link](https://stackoverflow.com/questions/50671555/creating-multiple-pages-with-tkinter-without-using-class) – Aleksandar Beat Jun 03 '18 at 23:18
  • @Bryan: Is there some reason why you didn't have the `Button`s in `MainView` call the `show()` method instead of `lift()`? I ask because of question [tkinter: How to print a list when a Button is clicked?](https://stackoverflow.com/questions/67893128/tkinter-how-to-print-a-list-when-a-button-is-clicked) – martineau Jun 08 '21 at 21:36
  • @martineau: that was a mistake. Thanks for pointing it out, I've updated the answer. – Bryan Oakley Jun 08 '21 at 22:04
7

Could you do something like this?

import tkinter

def page1():
    page2text.pack_forget()
    page1text.pack()

def page2():
    page1text.pack_forget()
    page2text.pack()

window = tkinter.Tk()

page1btn = tkinter.Button(window, text="Page 1", command=page1)
page2btn = tkinter.Button(window, text="Page 2", command=page2)

page1text = tkinter.Label(window, text="This is page 1")
page2text = tkinter.Label(window, text="This is page 2")

page1btn.pack()
page2btn.pack()
page1text.pack()

It seems a lot simpler to me.

William Jones
  • 809
  • 2
  • 11
  • 29
-2
import tkinter as tk
root=tk.Tk()
root.geometry("360x360")

frame=tk.Frame(root,bg='lightblue')
frame.place(relx=0.2,rely=0.2,relheight=0.6,relwidth=0.6)

def page1():
    label=tk.Label(frame,text='this is the page1')
    label.place(relx=0.3,rely=0.4)

def page2():
    label=tk.Label(frame,text='this is the page2')
    label.place(relx=0.3,rely=0.4)

def page3():
    label=tk.Label(frame,text='this is the page3')
    label.place(relx=0.3,rely=0.4)

bt=tk.Button(root,text='page1',command=page1)
bt.grid(column=0,row=0)

bt1=tk.Button(root,text='page2',command=page2)
bt1.grid(row=0,column=1)

bt2=tk.Button(root,text='page3',command=page3)
bt2.grid(row=0,column=2)

root.mainloop()`
  • 3
    Please add an explanation to your code: What does it do, how does it work, how does it solve OPs problem, and what makes it different from the existing answers. Code only answers can lead to [cargo cult programming](https://en.wikipedia.org/wiki/Cargo_cult_programming), and you risk getting downvotes. – Max Vollmer Dec 10 '19 at 12:23