My Complaint
I am currently delving deeper than "ever" before into the Tkinter GUI, and I have found the .grid()
geometry manager to be inadequate for several reasons:
The plots are based on the largest widget within them - this relativity leads to inaccuracy.
In Windows 7, on Python 2.7.3, the program does not seem to heed my row numbers, instead preferring to use the order of the widgets.
My Code
I am currently working on a really basic text editor, and I want to have multiple buttons on the top of the frame. I have been unable to do this as my widgets are placed either to the far left or right of the massive textbox that dominates the center of the screen.
========Class __init__ Stuff============
def widget(self):#Place widgets here
#Save Button
self.saveButton = Button (self, text = "Save", command = self.saveMe)
self.saveButton.grid(column = 0, row = 0, sticky = W)
#Open Button
self.openButton = Button (self, text = "Open", command = self.openMe)
self.openButton.grid(column = 0, row = 1, sticky = W)
#Area where you write
self.text = Text (self, width = (root.winfo_screenwidth() - 20),
height = (root.winfo_screenheight() - 10))
self.text.grid(row = 2)
==============Mainloop/Command Stuff============
My Question
Is there another way to use the .grid()
geometry manager in a way that is more accurate, or should I be using another function altogether?
Thanks!
pack is the easiest layout manager to use with Tkinter. However, pack() is limited in precision compared to place() and grid() which feature absolute positioning. For simple positioning of widgets vertically or horizontally in relation to each other, pack() is the layout manager of choice.
Tkinter has three built-in layout managers: the pack , grid , and place managers. The place geometry manager positions widgets using absolute positioning. The pack geometry manager organizes widgets in horizontal and vertical boxes.
In Tkinter there are three types of layout managers -- pack , place , and grid . Each manager uses a different method to help us arrange widgets.
There are 3 geometry managers that you have available to you -- grid
, pack
and place
. The third is the most general, but also very difficult to use. I prefer grid
. Note that you can place widgets inside of other widgets -- Or you can specify columnspan
. So, if you want to get the following layout:
-------------------------
| Button1 | Button2 |
-------------------------
| Big Widget |
-------------------------
there are 2 canonical ways to do it using .grid
. The first method is columnspan
:
import Tkinter as Tk
root = Tk.Tk()
b1 = Tk.Button(root,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(root,text="Button2")
b2.grid(row=0,column=1)
big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0,columnspan=2)
*note that there is a completely analogous rowspan
option as well.
The second method is to use a Frame
to hold your buttons:
import Tkinter as Tk
root = Tk.Tk()
f = Tk.Frame(root)
f.grid(row=0,column=0)
#place buttons on the *frame*
b1 = Tk.Button(f,text="Button1")
b1.grid(row=0,column=0)
b2 = Tk.Button(f,text="Button2")
b2.grid(row=0,column=1)
big_widget = Tk.Canvas(root)
big_widget.grid(row=1,column=0) #don't need columnspan any more.
This method is SUPER useful for creating complex layouts -- I don't know how you could create a complex layout without using Frame
objects like this ...
The "best" geometry manager depends on what you want to do, no geometry manager is best for all situations. For what you're trying to do in this specific case, pack is probably the better choice. Also note that there may be more than one "best" in an application. It's quite normal to use both grid and pack in different parts of your applications. I rarely ever create a GUI where I don't use both grid and pack. And rarely, I also use place.
pack excels at placing things in single rows and single columns. Toolbars, for example, are a perfect case for using pack since you want all your buttons aligned to the left. grid, as it name implies, is best when you want fixed rows and columns. place is useful in those rare cases where neither grid nor pack will do, since it allows you to place widgets at precise fixed or relative locations.
My advice is to divide your application widgets into groups, and use the right geometry manager for each group. In your case you have two logical groups: the toolbar along the top, and a text-widget-and-scrollbar combination in the bottom. So, start with two frames. Since the toolbar is on top and the text widget is below, pack works best.
toolbar = tk.Frame(...)
main = tk.Frame(...)
toolbar.pack(side="top", fill="x", expand=False)
main.pack(side="bottom", fill="both", expand=True)
The above now gives you two areas that are easy to modify independently.
For the toolbar, pack is again most natural. In this case, however, you want the buttons along the left instead of along the top or bottom:
b1 = tk.Button(toolbar, ...)
b2 = tk.Button(toolbar, ...)
b1.pack(side="left")
b2.pack(side="left")
...
Finally, the bottom area. Your example code doesn't show scrollbars, but I assume at some point you'll want to add them. grid works well if you're using both horizontal and vertical scrollbars. I would lay them out like this:
hsb = tk.Scrollbar(main, ..., orient="horizontal", ...)
vsb = tk.Scrollbar(main, ..., orient="vertical", ...)
text = tk.Text(main, ...)
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
text.grid(row=0, column=0, sticky="nsew")
main.grid_rowconfigure(0, weight=1)
main.grid_columnconfigure(0, weight=1)
That last part is important -- you always need to give a weight to at least one row and one column. This tells grid which rows and columns should grow and shrink when the window is resized.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With