I'm new to Tkinter and python. I'm following Switch between two frames in tkinter to see switch frames and it worked. Next, I'm trying to write the code for switch frames inside Page One, but I don't have any idea how to do it.
Below is the code:
from tkinter import *
import tkinter as tk
from tkinter import font 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")
# 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)
width = 1350 # 1280
height = 720
screen_width = self.winfo_screenwidth()
screen_height = self.winfo_screenheight()
x = (screen_width / 2) - (width / 2)
y = (screen_height / 2) - (height / 2)
self.geometry(f'{width}x{height}+{int(x)}+{int(y)}')
self.resizable(False,False)
self.frames = {}
for F in (StartPage, PageOne):
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"))
button1.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
LeftFrame=tk.Frame(self,relief=RIDGE, bd=2)
LeftFrame.place(x=0,y=0,width=160,height=720)
button = tk.Button(LeftFrame, text="Go to the start page",font=("bold"),command=lambda: controller.show_frame("StartPage"))
button.grid(row=0)
buttonBlue = tk.Button(LeftFrame, text="Go to the blue page",bg="blue",fg="white",command=self.blue,activebackground="blue",activeforeground="white")
buttonBlue.grid(row=1)
buttonRed = tk.Button(LeftFrame, text="Go to the red page",bg="red",fg="white",command=self.red,activebackground="red",activeforeground="white")
buttonRed.grid(row=2)
buttonYellow = tk.Button(LeftFrame, text="Go to the yellow page",bg="yellow",fg="black",command=self.yellow,activebackground="yellow",activeforeground="black")
buttonYellow.grid(row=3)
def blue(self):
# self.hide_all_frames()
blueFrame=tk.Frame(self,relief=RIDGE,bd=1 ,bg="blue")
blueFrame.place(x=160,y=0,width=1190,height=720)
def red(self): # Do I need to put self here? It still worked without putting self here
# self.hide_all_frames()
redFrame=tk.Frame(self,relief=RIDGE,bd=1 ,bg="red")
redFrame.place(x=200,y=0,width=1150,height=720)
def yellow(self):
# self.hide_all_frames()
yellowFrame=tk.Frame(self,relief=RIDGE,bd=1 ,bg="yellow")
yellowFrame.place(x=240,y=0,width=1110,height=720)
def hide_all_frames(self):
self.blue.withdraw()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
When I switch to Page One, I create a couple of buttons to switch color frames. They all overlap every time I switch between colors like the image below.
I'm finding a way to switch color frames without overlapping each other. And, when I go back to the Start Page, all color frames should be destroyed/hidden. Please help me. Thank you so much.
For the frame switching inside PageOne, you need to hide the current frame before showing the requested frame. Also it is better to create the three color frames in the __init__() and show it in the corresponding function:
class PageOne(tk.Frame):
def __init__(self, parent, controller):
...
# create the three color frames with initially hidden
self.blueFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="blue")
self.redFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="red")
self.yellowFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="yellow")
def blue(self):
self.hide_all_frames()
self.blueFrame.place(x=160, y=0, width=1190, height=720)
def red(self):
self.hide_all_frames()
self.redFrame.place(x=200, y=0, width=1150, height=720)
def yellow(self):
self.hide_all_frames()
self.yellowFrame.place(x=240, y=0, width=1110, height=720)
def hide_all_frames(self, event=None):
self.redFrame.place_forget()
self.blueFrame.place_forget()
self.yellowFrame.place_forget()
If you want to hide all color frames after switching frames, i.e. PageOne -> MainPage -> PageOne, you can notify the PageOne using virtual event when it is raised. Then PageOne hides all the color frames upon receiving such virtual event:
class SampleApp(tk.Tk):
...
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
# notify the raised frame via virtual event
frame.event_generate('<<Raised>>')
...
class PageOne(tk.Frame):
def __init__(self, parent, controller):
...
self.blueFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="blue")
self.redFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="red")
self.yellowFrame = tk.Frame(self, relief=RIDGE, bd=1, bg="yellow")
self.bind('<<Raised>>', self.hide_all_frames)
Related
I was reading this tutorial of StackOverflow on how to get variables among classes, but I'm not able to make it work. Basically what i want to do is to pass an entry value from StartPage to PageOne where i need it. I also tried "the wrong way" using global variables, but I need an int and I can't covert the string entry to an int. Down below there's my code, can you help me please?
import tkinter as tk # python 3
from tkinter import font as tkfont
from typing_extensions import IntVar # python 3
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):
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()
def get_page(self, classname):
'''Returns an instance of a page given it's class name as a string'''
for page in self.frames.values():
if str(page.__class__.__name__) == classname:
return page
return None
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Start Page: insert value", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
self.valore = tk.IntVar()
entry = tk.Entry(self, textvariable=self.valore).pack()
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
start_page = self.controller.get_page("StartPage")
value = start_page.entry.get()
print ('The value stored in StartPage entry = %s' % value)
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()
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I'm implementing a GUI with Tkinter following this topic: Switch between two frames in tkinter
Trying to adapting it to my problem:
This is the controller:
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title('VOICED/UNVOICED SPEECH DETECTION')
self.resizable(RESIZABLE, RESIZABLE)
self.geometry(str(WIDTH_WINDOW) + 'x' + str(HEIGHT_WINDOW))
self.configure(bg=BACK_GROUND_COLOR)
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 (HomePage, MenuPage, GraphicPage):
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("HomePage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
This is the home page that shows the lateral bar:
And the corresponding code:
class HomePage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.bg = BACK_GROUND_COLOR
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
# -----------ROOT WINDOWS-------------
self.configure(bg=BACK_GROUND_COLOR)
self.position = 0
# ----------Menu Bar-------------------------
self.menu_frame = tk.Frame(master=self, height=HEIGHT_WINDOW, width=50,
borderwidth=5, relief='groove', highlightbackground="black",
highlightcolor="black", highlightthickness=1, bg=BACK_GROUND_COLOR).place(x=0, y=0)
# Menu Button
self.menu_img = tk.PhotoImage(file='frontend/Widget/icons/menu.png')
self.menu_button = tk.Button(master=self.menu_frame, image=self.menu_img,
height=25, width=25,
command=lambda: controller.show_frame("MenuPage"),
bg=BACK_GROUND_COLOR).place(x=10, y=10)
# Back Button
self.back_img = tk.PhotoImage(file='frontend/Widget/icons/back.png')
self.back_button = tk.Button(master=self.menu_frame, image=self.back_img, height=25, width=25,
bg=BACK_GROUND_COLOR).place(x=10, y=46)
# Home Button
self.home_img = tk.PhotoImage(file='frontend/Widget/icons/home.png')
self.home_button = tk.Button(master=self.menu_frame, image=self.home_img, height=25, width=25,
bg=BACK_GROUND_COLOR).place(x=10, y=82)
When I click the menu button (the first in the lateral bar), I obtain the menu option (That I called MenuPage):
And the corresponding code:
class MenuPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.bg = BACK_GROUND_COLOR
# --------------------------------------------------toolbar--------------------------------------
self.toolbar_frame = tk.Frame(master=self, height=70, width=WIDTH_WINDOW - 54,
borderwidth=5, relief='groove', highlightbackground="black",
highlightcolor="black",
highlightthickness=1, bg=BACK_GROUND_COLOR).place(x=51, y=0)
self.button_graphics_img = tk.PhotoImage(file='frontend/Widget/icons/graphic.png')
self.button_graphic = tk.Button(master=self, text='Test/Train',
image=self.button_graphics_img, height=25, width=25, bg=BACK_GROUND_COLOR,
command=lambda: controller.show_frame("GraphicPage")).place(x=75, y=5)
self.label_graphic = tk.Label(master=self, text='Plot Parameters',
height=0, width=12, bg=BACK_GROUND_COLOR).place(x=55, y=40)
As you can notice, when I click on the menu button the lateral frame disappears. This is because in the MenuPage there aren't the methods of the lateral bar, but trying to put it also in the MenuPage, the buttons (back arrow, home) don't work.
So I don't get how to hold fixed the lateral bar for all my pages and make sure that the buttons do their job.
Any suggestions will be appreciated.
Thanks in advance
UPDATE:
By placing the sidebar in the Main Windows, I solved the fact that the sidebar disappeared when I opened the menu.
The other problem is:
How can I do with the back arrow to come back to the previous Frame? For Instance, if I open another page with a button in the MenuPage, and then I'd want to come back to from that page to the MenuPage, how should I do?
I've already tried to re-place the buttons in the page opened from menu changing the command to open the previous page (putting lambda: controller.show_frame("MenuPage") ) but doesn't works.
I use following code:
Switch between two frames in tkinter
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
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):
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)
self.giris = tk.Entry(self)
self.giris.pack()
self.yazi = tk.Label(self, text="Buraya GİRİLEN VERİ gelecek.")
self.yazi.pack()
button2 = tk.Button(self, text="ae",
command=lambda: [self.alinanmetin(), controller.show_frame("PageOne")])
button2.pack()
def alinanmetin(self):
il = self.giris.get()
self.yazi.config(text="Girdiğiniz il: %s" % il)
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()
if __name__ == "__main__":
app = SampleApp()
app.geometry("600x400")
app.mainloop()
I want to change my frame according to the value I get from the entry.
if(il =="ali") i want change my frame and
if( il != "ali") i dont want do anything.
I am currently running two functions at the same time.How can i change frame after check value.
I'm trying to make a calculator and it has different frames i.e Basic, Statistics, ..., etc. However, I'm having issues to show each frame.
This is the container for all the frames (I took a code of a previous post as example)
import tkinter as tk
class calculatorframe(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
#----------------CONTAINER FOR ALL THE FRAMES----------
container = tk.Frame(self)
container.pack()
#--------------------- DROPDOWN MENU------------------
tkvar = tk.StringVar()
choices={'Basic Mode','Calculus Mode'} #Options of the dropdown menu
tkvar.set('Basic Mode') #default frame
dropdownmenu =tk.OptionMenu(container, tkvar, *choices)
dropdownmenu.grid(row=2,column=3) #position of the dropdown menu
self.frames = {}
for F in (Basic, Calculus):
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('Basic')
#-------FUNCTION TO SHOW THE CURRENT FRAME
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
These are the classes that I created for the basic calculator
class Basic(tk.Frame):
def __init__(self, parent, controller):
#--------------- SCREEN ---------------
tk.Frame.__init__(self, parent)
screen = tk.Entry(self, width=80)
screen.grid(row=3, column=1,columnspan=7) #position of the screen
#------------ BUTTON ---------------------
button7=tk.Button(self, text="7", width=8) #button
button7.grid(row=4,column=1)
#---------------------frame for calculus -------------------------
class Calculus(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
#-----------------------------SCREEN------------
screen=tk.Entry(self, width=50)
screen.pack()
screen.grid(row=3, column=1, pady=20, columnspan=7) #position of the screen
#------------------------BUTTON---------------
go=tk.Button(self, height=1, text="Go") #button
go.grid(row=1, column=8)
if __name__ == "__main__":
app = calculatorframe()
app.mainloop()
I'm aware that I have to keep track of the value of tkvar and that I need to do it using trace() and pass that value to show_frame, however, I don't know where to place it in my code. I tried to put it below the dropdown menu, but I get an error message and I tried after the function show_frame and it did not work either. I'm a bit stuck, I would really appreciate your help, thanks in advance.
The simple solution would be to add a command to your OptionsMenu() function. We will also need to change your class names and your choice options due to how the command argument works here.
For the OptionsMenu() command argument when you tell it to call a method it will automatically pass the value of the selected item in the drop down. So because of this we need to make sure our selection reflect the class names. You can change the choices/classes to be whatever you wish I just used BasicMode and CalculusMode as an example.
The command will automatically pass the value selected so we can use that to call each frame using you show_frame method.
Take a look at the below code and let me know if you have any questions.
import tkinter as tk
class calculatorframe(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container = tk.Frame(self)
container.pack()
tkvar = tk.StringVar()
choices = {'BasicMode', 'CalculusMode'}
tkvar.set('BasicMode')
dropdownmenu = tk.OptionMenu(container, tkvar, *choices, command=self.show_frame)
dropdownmenu.grid(row=2, column=3)
self.frames = {}
for F in (BasicMode, CalculusMode):
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('BasicMode')
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class BasicMode(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
screen = tk.Entry(self, width=80)
screen.grid(row=3, column=1, columnspan=7)
button7 = tk.Button(self, text="7", width=8)
button7.grid(row=4,column=1)
class CalculusMode(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
screen = tk.Entry(self, width=50)
screen.pack()
screen.grid(row=3, column=1, pady=20, columnspan=7)
go = tk.Button(self, height=1, text="Go")
go.grid(row=1, column=8)
if __name__ == "__main__":
app = calculatorframe()
app.mainloop()
I am trying to make a tkinter widow with multiple frames, but also the functions of notebook, like multiple widows. The problem is I am kind of unfamiliar with tkinter and am not sure how to do that. This is my current code, and it doesn't work, and would love to know what I should do to make it work. Again, the dream end result would be that I would have a first widow, which says the test text, and then the 2nd window which has multiple tabs.
from tkinter import ttk
import tkinter as tk
Font= ("Verdana", 8)
LargeFont = ("Verdana", 12)
class App(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
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):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
label = tk.Label(self, text="Info", font=LargeFont)
label.pack(pady=2,padx=10)
text = tk.Label(self, text="testtestestetetqwegfegeg\ntestwegwegwegweg", font=Font)
text.pack(pady=2,padx=2)
button = tk.Button(self, text="Go to the Card",
command=lambda: controller.show_frame(PageOne))
button.pack(fill="x")
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
nb = ttk.Notebook(ttk.Frame())
nb.grid(row=1, column=0, columnspan = 50, rowspan=49, sticky='nesw')
p1 = (nb)
nb.add(p1, text='test')
label = tk.Label(self, text="", font=LargeFont)
label.pack(pady=10,padx=10)
button1 = tk.Button(self, text="Back to Home",
command=lambda: controller.show_frame(StartPage))
button1.pack()
app = App()
app.mainloop()
The error that I eventually get is that it creates a third frame that is displayed with the test tab. Everything else works.
Thanks for your help
I know exactly what you mean because I'm trying the same. To me
nb = ttk.Notebook(self)
worked.
best
Pkanda
Taubate Brazil