What is a better Tkinter geometry manager than .grid ()

My complaint

I am currently delving deeper than ever in the Tkinter GUI, and I have found that the .grid() geometry .grid() inadequate for several reasons:

  • Charts are based on the largest widgets inside them - this relativity leads to inaccuracies.

  • On Windows 7, on Python 2.7.3, the program does not seem to take my line numbers into account; instead, it prefers to use the order of the widgets.

My code

I'm currently working on a really basic text editor, and I want to have some buttons at the top of the frame. I could not do this, because my widgets are placed either in the leftmost or to the right of the massive text field 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 .grid() more accurate, or should I use another function at all?

Thanks!

+4
source share
4 answers

There are 3 geometry managers that are available to you - grid , pack and place . The third is the most common, but also very difficult to use. I prefer grid . Note that you can place widgets inside other widgets - or you can specify columnspan . So, if you want the following layout:

  ------------------------- | Button1 | Button2 | ------------------------- | Big Widget | ------------------------- 

There are 2 canonical ways to do this using .grid . First method: 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 similar rowspan option.

The second way is to use Frame to hold the 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 SUPER method is useful for creating complex layouts - I don’t know how you could create a complex layout without using Frame objects like this ...

+14
source

The "best" geometry manager depends on what you want to do; no geometry manager is suitable for all situations. For what you are trying to do in this particular case, the package is probably the best choice. Also note that there may be several "best" in the application. It is quite normal to use both the grid and the package in different parts of your applications. I rarely ever create a GUI where I don't use both the grid and the package. And rarely, I also use the place.

pack differs in that it is placed in separate rows and separate columns. Toolbars, for example, are ideal for using the package, because you want all of your buttons to be left-aligned. a grid, as the name suggests, is best when you want fixed rows and columns. the place is useful in those rare cases when neither the grid nor the package will be done, since this allows you to place widgets in an exact fixed or relative location.

My advice is to split application widgets into groups and use the correct geometry manager for each group. In your case, you have two logical groups: a toolbar at the top and a combination of text and a widget and a scroll at the bottom. So, start with two frames. Since the toolbar is on top and the text widget is below, the package 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 gives you two areas that are easy to change independently.

For a toolbar, a package is again the most natural. In this case, however, you need the buttons on the left, not the top or bottom:

 b1 = tk.Button(toolbar, ...) b2 = tk.Button(toolbar, ...) b1.pack(side="left") b2.pack(side="left") ... 

Finally, the lower region. In your code example, the scroll bars are not displayed, but I assume that at some point you will want to add them. the grid works well if you use horizontal and vertical scrollbars. I would put them 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) 

This last part is important - you always need to give weight to at least one row and one column. This indicates the grid whose rows and columns should grow and shrink when the window is resized.

+5
source

I find the place manager the most intuitive and accurate of all three, due to the ability to specify combinations of absolute and relative length for both positions and size:

 mywidget.place(x=..., y=..., width=..., height=...) # absolute mywidget.place(relx=..., rely=..., relwidth=..., relheight=...) # relative # combination pad_left=5 pad_right=5 pad_top=5 pad_bottom=5 mywidget.place(relx=0, x=pad_left, rely=0, y=pad_top,\ relwidth=1, width=-pad_left-pad_right,\ relheight=1, height=-pad_top-pad_bottom, anchor="e") # use the whole space except some padding 

For some reason, the .place manager .place n't really like it, but I think it's especially important to determine how your widgets should move and resize when the parent window is resized.

To facilitate the construction of complex windows, I sometimes use a function (for example, to emulate the behavior of a grid) to help with vertical placement, for example:

 def offset_y(line_no): if line_no == 0: return 0 else: return height_label + (line_no - 1)*height_button mylabel.place(..., y=offset_y(0)) mybtn1.place(..., y=offset_y(1)) etc. 

to pack a shortcut vertically and then a few buttons. (Of course, the .pack manager can be used in this case, but the reason I prefer the .place manager is to have a better understanding of how things will move when the window is resized).

0
source

Instead of row, column .... etc. you can use the coordinates.

It may be easier than others.

Example:

 from Tkinter import* root=Tk() Button(root,text="HI").grid(padx=100,pady=50) root.mainloop() 

Try it yourself by changing the padx and pady values.

-2
source

All Articles