Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tkinter: grid or pack inside a grid?

I am building a GUI for a software and want to achieve this:

######################################
#             |      some title      #
# menu upper  |----------------------#
#             |                      #
#             |         CANVAS       #
# menu lower  |                      #
#             |                      #
#------------------------------------#
#              statusbar             #
######################################

Menu upper has some high level functionality, menu lower is changing in dependency of user input. Statusbar changes its contents often.


Unfortunately, Tkinter refuses to work.

Using the grid layout manager I were unable to create a stable design and adding content like labels and buttons to the menu on the left side:

self.root = tk.Tk()
self.root.resizable(width=0, height=0)
self.root.title("some application")

# menu left
self.menu_left = tk.Frame(self.root, width=150, bg="#ababab")
self.menu_left.grid(row=0, column=0, rowspan=2, sticky="ns")

self.menu_left_upper = tk.Frame(self.menu_left, width=150, height=150, bg="red")
self.menu_left_upper.grid(row=0, column=0)

# this label breaks the design   
#self.test = tk.Label(self.menu_left_upper, text="test")
#self.test.pack()

self.menu_left_lower = tk.Frame(self.menu_left, width=150, bg="blue")
self.menu_left_lower.grid(row=1, column=0)

# right area
self.some_title_frame = tk.Frame(self.root, bg="#dfdfdf")
self.some_title_frame.grid(row=0, column=1, sticky="we")

self.some_title = tk.Label(self.some_title_frame, text="some title", bg="#dfdfdf")
self.some_title.pack()

self.canvas_area = tk.Canvas(self.root, width=500, height=400, background="#ffffff")
self.canvas_area.grid(row=1, column=1)

self.root.mainloop()

This design worked without contents in the menu on the left side. Whenever I added something in self.menu_left_upper or self.menu_left_lower, like the test label, my design got broke: the menu frames disappeared. Additionally, even with columnspan, I had to remove the statusbar, because when it was added the menus on the left disappeared, again.


Using pack layout manager I got this:

######################################
#             |      some title      #
#             |----------------------#
# menu upper  |                      #
#             |         CANVAS       #
#             |                      #
# menu lower  |                      #
#             |----------------------#
#             |       statusbar      #
######################################

Since I wanted the menu frame on the left to consume the full y-space I made it grow with pack(side="left", expand=True, fill="both"), but this setup always denies the statusbar to go for the full width.

Besides, the pure pack manager code looks "ugly". I think a design with a grid manager is "clearer". Therefore I thought a grid or a pack layout inside a grid layout would be nice?


Can anyone help? I am stuck in the GUI-hell :/

like image 509
daniel451 Avatar asked Apr 08 '16 17:04

daniel451


1 Answers

By putting in the line:

menu_left_upper.grid_propagate(False) 

In between your menu_left_upper Frame and menu_left_upper.mainloop()

This works as:

By default, a container widget expands or collapses to be just big enough to hold its contents. Thus, when you call pack, it causes the frame to shrink. This feature is called geometry propagation.

For the vast majority of applications, this is the behavior you want. For those rare times when you want to explicitly set the size of a container you can turn this feature off. To turn it off, call either pack_propagate or grid_propagate on the container (depending on whether you're using grid or pack on that container), giving it a value of False.

See link to another question where this came from

To get your status bar just implement another frame and grid method:

status_bar_frame = Frame(root, bg="#dfdfdf")
status_bar_frame.grid(row=3, column=0, columnspan=2, sticky="we")

status_bar = Label(status_bar_frame, text="status bar", bg="#dfdfdf")
status_bar.pack()

Then your plan works. Hope it helps :)

PS. Also why all the self attributes?

EDIT: TO work you need to do:

menu_left_upper = Frame(menu_left, width=225, height=225, bg="red")
menu_left_upper.grid_propagate(False)
menu_left_upper.grid(row=0, column=0)

# this label breaks the design   
test = Label(menu_left_upper, text="test", bg='red')
test.grid()

My result

like image 67
Benno_S Avatar answered Sep 28 '22 01:09

Benno_S