Just started learning tkinter and im tackling on grid management.
I set the a frame to have 1 weight on column 0, therefore I expected label1 to be stretched to the end of the frame, then label2 added on column 1 with the length relative to its text size.
expected output: https://gyazo.com/65cf907e2cdea07d08844bdc8c62c7b2
output: https://gyazo.com/3c9e9c9f86372e01e96283545387c51e
Heres my code:
import tkinter as tk
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)
frame_list = (MenuFrame,
)
self.geometry("1024x768")
self.frames = {}
for F in frame_list:
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("MenuFrame")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class MenuFrame(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.create_widgets(self)
def create_widgets(self, parent):
frame = tk.Frame(self, bg="white")
frame.grid_columnconfigure(0, weight=1)
frame.grid_rowconfigure(0, weight=1)
label1 = tk.Label(frame, text="Label one", bg="red")
label2 = tk.Label(frame, text="Label two", bg="blue", fg="white")
frame.grid(row=0, column=0, sticky="nsew")
label1.grid(row=0, column=0)
label2.grid(row=0, column=1)
if __name__ == "__main__":
app = App()
app.mainloop()
You are properly configuring the weight for frame. However, frame hasn't been properly configured to fill the window. Because of that, it's just barely wide enough for the two labels and thus the weight has no effect.
Since frame seems to be the only widget inside the class MenuFrame, I would use pack instead of grid since it only requires one line:
frame.pack(fill="both", expand=True)
If you prefer using grid, then you need to also configure the weight for its parent.
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
frame.grid(row=0, column=0, sticky="nsew")
Related
class View(tkinter.Tk):
def __init__(self):
tkinter.Tk.__init__(self)
self.geometry("500x500")
self.title("Switch Frame Example")
container_frame = tkinter.Frame(self)
container_frame.pack(side="top", fill="both", expand=True)
container_frame.grid_rowconfigure(0, weight=1)
container_frame.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (RedFrame, GreenFrame):
frame_name = F.__name__
frame = F(container_frame, self)#container_frame is the parent, self (the window) is the controller
self.frames[frame_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("RedFrame")
def show_frame(self, frame_name):
frame = self.frames[frame_name]
frame.tkraise()
class RedFrame(tkinter.Frame):
def __init__(self, parent, window):
tkinter.Frame.__init__(self, parent, bg="red", width="500", height="500")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_propagate(0)
goto_green_button = tkinter.Button(self, text='green frame', fg="green", width=25, command=lambda: window.tkraise("GreenFrame"))
goto_green_button.grid(row=0, column=0)
class GreenFrame(tkinter.Frame):
def __init__(self, parent, window):
tkinter.Frame.__init__(self, parent, bg="green", width="500", height="500")
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.grid_propagate(0)
goto_red_button = tkinter.Button(self, text='red frame', fg="red", width=25, command=lambda: window.tkraise("RedFrame"))
goto_red_button.grid(row=0, column=0)
The title of this post is the error I get when trying I click the goto_green_button. I used Bryan Oakley's code taken from this post as the basis for mine, but I'm not sure what I've done wrong, since his code actually works as it should, while mine does not. Why is "GreenFrame" a bad window path? It has the exact same name as the "GreenFrame" class, so shouldn't it work? Or does it have to do with the order of the frames and which is above the other?
I have the menu frame on the left side and the main container on the right side but when I fire it up I only see them in a small box inside the main window.
How can I make the frames fit the window no matter what size it is?
Code:
class GUI(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title("GUI Project")
# self.resizable(0, 0)
menu = tk.Frame(self, relief="solid")
container = tk.Frame(self, relief="ridge")
menu.grid(row=0, column=0, rowspan=4, sticky="nsew")
container.grid(row=0, column=1, sticky="nsew")
menu.grid_rowconfigure(0, weight=1)
container.rowconfigure(0, weight=0)
container.columnconfigure(1, weight=0)
self.frames = ["Menu", "FutureFeature2", "TestPing", "FutureFeature3", "FutureFeature"]
self.frames[0] = Menu(parent=menu, controller=self)
self.frames[1] = FutureFeature2(parent=container, controller=self)
self.frames[2] = TestPing(parent=container, controller=self)
self.frames[3] = FutureFeature3(parent=container, controller=self)
self.frames[4] = FutureFeature(parent=container, controller=self)
self.frames[0].grid(row=0, column=0, sticky="nsew")
self.frames[1].grid(row=0, column=0, sticky="nsew")
self.frames[2].grid(row=0, column=0, sticky="nsew")
self.frames[3].grid(row=0, column=0, sticky="nsew")
self.frames[4].grid(row=0, column=0, sticky="nsew")
self.show_frame(1)
def show_frame(self, page_name):
frame = self.frames[page_name]
print(frame)
frame.tkraise()
frame.grid(row=0, column=0, columnspan=5, rowspan=5, sticky="nsew")
class Menu(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
button1 = tk.Button(self, text="Ping Test", bg="royalblue2",
command=lambda: controller.show_frame(2))
button2 = tk.Button(self, text="FutureFeature", bg="dark violet",
command=lambda: controller.show_frame(4))
buttun3 = tk.Button(self, text="FutureFeature", bg="pale goldenrod",
command=lambda: controller.show_frame(1))
button4 = tk.Button(self, text="Quit", bg="gray40",
command=lambda: self.terminate())
button1.pack(fill="both", expand=True)
button2.pack(fill="both", expand=True)
buttun3.pack(fill="both", expand=True)
button4.pack(fill="both", expand=True)
def terminate(self):
path = fr'c:/users/{os.getlogin()}/desktop/Gui-Skeleton'
try:
os.rmdir(path)
except OSError as err:
print(f"Error Deleting tmp folder! {err}")
exit()
if __name__ == "__main__":
path = fr'c:/users/{os.getlogin()}/desktop/Gui-Skeleton'
try:
if os.path.isdir(path):
pass
else:
os.mkdir(path)
except OSError as err:
print(f"[!] Operation failed! {err}")
app = GUI()
app.geometry("800x600")
app.mainloop()
.....................................................................................................................................................................................................................................................................................
The specific problem that you're asking about is due to the fact you are putting menu and container in the root window using grid but you haven't given any rows or columns in the root window a weight. Therefore, both menu and grid will use as little space as necessary.
A general rule of thumb is that when you use grid, you should give at least one row and one column a positive weight so that there is no unused space. You are failing to do that in the root window. For more information on grid weights see What does 'weight' do in tkinter?
The solution is simple: make sure that you've given at least one row and one column a positive weight in the root window:
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=1)
That being said, I would recommend using pack for menu and container since they are the only widgets directly in the root window. pack is generally better than grid when laying out widgets in row or column, if for no other reason that you don't have to take the extra step of assigning weights.
menu.pack(side="left", fill="y")
container.pack(side="right", fill="both", expand=True)
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 am using a template that I saw in a youtube video for my app. I have split the window in 3 using 3 frames. All 3 frames are nested into a main frame. The main frame is attached directly to the root window.
I am using pack manager in order to place mainframe inside the root window.
I am using grid manager in order to place the 3 frames inside the mainframe.
The issue that I'm facing is that when I try to resize the window the left frame gets resized more than the other 2 frames, and I don't understand why that happens. I need the frames to resize proportionately to each other. Why is the left frame getting resized more than the others? and how can I correct this?
import tkinter as tk
from tkinter import ttk
Normal_Font = ('Verdana', 9)
Large_font = ('Verdana', 12)
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
mainframe = tk.Frame(self)
mainframe.pack(side='top', fill='both', expand=True)
mainframe.grid_rowconfigure(0, weight=1)
mainframe.grid_columnconfigure(0, weight=1)
#mainframe.grid(row=0, column=0, sticky='nesw')
#left frame
employerframe = tk.Frame(mainframe)
employerframe.grid(row=0, column=0, sticky='nesw')
employerframe.grid_rowconfigure(0, weight=1)
employerframe.grid_columnconfigure(0, weight=1, uniform=1)
label1 = tk.Label(employerframe, text='Employer Frame', font=Large_font)
label1.grid(row=0, column=0, sticky='nesw')
ttk.Separator(mainframe, orient=tk.VERTICAL) .grid(row=0, column=1, sticky='ns')
#right frame
candidateframe = tk.Frame(mainframe)
candidateframe.grid(row=0, column=4, sticky='nesw')
candidateframe.grid_rowconfigure(0, weight=1)
candidateframe.grid_columnconfigure(0, weight=1, uniform=1)
label2 = tk.Label(candidateframe, text='Candidate Frame', font=Large_font)
label2.grid(row=0, column=0, sticky='nesw')
ttk.Separator(mainframe, orient=tk.VERTICAL) .grid(row=0, column=3, sticky='ns')
#middle frame
container = tk.Frame(mainframe)
container.grid(row=0, column=2, sticky='nesw')
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1, uniform=1)
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky='nesw')
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='Start Page', font=Large_font)
label.pack(pady=10, padx=10)
app = MainApp()
app.mainloop()
It's because you are placing employerframe, container, candidateframe to column=0, column=2, column=4. But giving weight=1 to only column=0. you have to add the following lines also to give column, 0, 2, 4 equal weight.
mainframe.grid_columnconfigure(2, weight=1)
mainframe.grid_columnconfigure(4, weight=1)
Try This:
import tkinter as tk
from tkinter import ttk
Normal_Font = ('Verdana', 9)
Large_font = ('Verdana', 12)
class MainApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
mainframe = tk.Frame(self)
mainframe.pack(side='top', fill='both', expand=True)
mainframe.grid_rowconfigure(0, weight=1)
mainframe.grid_columnconfigure(0, weight=1)
# ----- Added lines -----
mainframe.grid_columnconfigure(2, weight=1)
mainframe.grid_columnconfigure(4, weight=1)
#left frame
employerframe = tk.Frame(mainframe)
employerframe.grid(row=0, column=0, sticky='nesw')
label1 = tk.Label(employerframe, text='Employer Frame', font=Large_font)
label1.grid(row=0, column=0, sticky='nesw')
ttk.Separator(mainframe, orient=tk.VERTICAL) .grid(row=0, column=1, sticky='ns')
#right frame
candidateframe = tk.Frame(mainframe)
candidateframe.grid(row=0, column=4, sticky='nesw')
label2 = tk.Label(candidateframe, text='Candidate Frame', font=Large_font)
label2.grid(row=0, column=0, sticky='nesw')
ttk.Separator(mainframe, orient=tk.VERTICAL) .grid(row=0, column=3, sticky='ns')
#middle frame
container = tk.Frame(mainframe)
container.grid(row=0, column=2, sticky='nesw')
self.frames = {}
frame = StartPage(container, self)
self.frames[StartPage] = frame
frame.grid(row=0, column=0, sticky='nesw')
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='Start Page', font=Large_font)
label.pack(pady=10, padx=10)
app = MainApp()
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