Skip to content Skip to sidebar Skip to footer

Some Elementary Tkinter Questions

I have a few questions regarding geometry managers: (a) How does the grid geometry managers determine the row and column ? I mean, how does grid manager indexes the master widget i

Solution 1:

a) The grid geometry manager only assigns space to the rows and columns that actually have some content. Therefore, if you only have one widget it does not matter what row and column you choose, the grid will effectively have one cell only (that is, unless you specify additional options with grid_rowconfigure or grid_columnconfigure, more about that in this tutorial and here).

b) With the pack geometry manager, the fill option indicates the widget that it has to expand its own size to fill the space assigned by the geometry manager. If you don't specify it, you may have some empty space surrounding the widget, for example if you put several widgets in a row and some are taller than other. The expand option, on the other hand, affects the amount of space that the geometry manager assigns to the widget; if you don't specify it, it will receive the minimum amount of space possible, otherwise any remaining space will be distributed among all the widgets that have expand set (more info here). So they are really independent things, one affects the size of the widget itself and the other the amount of window space it receives.

As for your last question, maybe you can provide a minimal example showing your problem.

Solution 2:

Essentially, with the .grid() method if you create an widget at position (0, 0) and the next widget is at position (100, 100), then the system will place the second widget in what appears to be (1, 1). This is because sequentially the second widget is in the "next position". You can think of it that positions (1, 1) to (99, 99) are still there but infinitely small, so (100, 100) looks like it's next to (0, 0), see below for an example:

from tkinter import *

root = Tk()

label1 = Label(root, text="Col0, Row0")
label2 = Label(root, text="Col100, Row100")

label1.grid(column=0, row=0)
label2.grid(column=100, row=100)

root.mainloop()

In regards to being able to place objects in opposite corners with .grid() this is possible and can be done using a combination of rowconfigure and columnconfigure's weight attribute, and the sticky attribute when using .grid() on the widget. See below:

from tkinter import *

root = Tk()

label1 = Label(root, text="1")
label2 = Label(root, text="2")

label1.grid(column=0, row=0, sticky="NW")
label2.grid(column=1, row=1, sticky="SE")

root.columnconfigure(0, weight=1)
root.rowconfigure(0, weight=1)

#Giving the rows and columns a weight that is not equal to 0#means that the rows and columns expand to fill the space in the window.#Then we assign a sticky value to the labels,#to position them where we need them in the cell.

root.columnconfigure(1, weight=1)
root.rowconfigure(1, weight=1)

root.mainloop()

If you're looking for more information on how the different attributes of .pack() work, I wrote this some time ago as the answer to another question and it should help with the fundamentals of using .pack():

from tkinter import *

root = Tk()
top = Toplevel()
top.withdraw()
var1 = StringVar(root)
var1.set("top")
var2 = StringVar(root)
var2.set("none")
var4 = StringVar(root)
var4.set("center")
var3 = BooleanVar(root)

def command(top, var1, var3, var2):
    top.destroy()
    top = Toplevel()
    top.geometry("500x500")
    Label(top, text="Welcome home").pack()
    Button(top, text="Button1").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
    Button(top, text="Button2").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
    Button(top, text="Button3").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())
    Button(top, text="Button4").pack(side=var1.get(), fill=var2.get(), expand=var3.get(), anchor=var4.get())

option1 = OptionMenu(root, var1, "top", "left", "bottom", "right")
check1 = Checkbutton(root, variable=var3, text="Expand?")
option2 = OptionMenu(root, var2, "none", "x", "y", "both")
option3 = OptionMenu(root, var4, "center", "n", "ne", "e", "se", "s", "sw", "w", "nw")
button1 = Button(root, text="Render", command=lambda:command(top, var1, var3, var2))

option1.pack()
check1.pack()
option2.pack()
option3.pack()
button1.pack()

root.mainloop()

Throw that into your editor of choice and play around with it.


I also want to point out that Stack Overflow isn't really the place for questions like this, I'd recommend finding documentation on the whatever it is you want to know before using SO.

For example, the best tkinter documentation (in my opinion) is: http://effbot.org/tkinterbook/

Solution 3:

I will do what I can to explain what is going on that is causing you this confusion about the geometry manager.

(a) How does the grid geometry managers determine the row and column ? I mean, how does grid manager indexes the master widget into row and column ?

The rows and columns are determined like you would expect. Your issue with a.grid(row=100,column=100) and a.grid(row=0, column=0) appearing the same is because of the nature of rows and columns. If a row or a column does not have any widgets in it then that row or column will just collapse to nothing. until such time something is placed inside of it.

So when you define a grid to have a widget at say row=1, column=1 you would expect in your head to get something like this.

*--------*--------*|||||||||*--------*--------*||row=1|||column|||=1|*--------*--------*

however because row 0 and column zero have no widgets in them then they collapse visibly to nothing and you get this:

*--------*|row=1||column||=1|*--------*

The other 3 cells still exist they just have no space being filled so they are as small as they can get resulting is visibly missing cells.

can you place a widget on topmost right and a widget on bottom most left, and the middle space empty, using grid ?

Yes you can. The same thing will happen as above and it will appear that the middle cell is gone however you can add some more parameters to your grid to allow for this to still appear as a 3 by 3. for example See the below code:

We can change the weight of a row or column to control the grid behavior.

from tkinter import *

classApplication():
    def__init__(self, master):

        self.master = master
        self.master.geometry("400x400")
        # the below column and row weights allow us to control the behavior of the grid.# setting the weight to 0 means the row or column will not resize at all# setting the number to 1 or higher will allow the row or column to resize with the window# what this does is allow us to keep widgets where we want them by manipulating the weights.
        self.master.columnconfigure(0, weight = 0)
        self.master.columnconfigure(1, weight = 1)
        self.master.columnconfigure(2, weight = 0)
        self.master.rowconfigure(0, weight = 0)
        self.master.rowconfigure(1, weight = 1)
        self.master.rowconfigure(2, weight = 0)

        top_left_label = Label(self.master, text="I am at the top left")
        top_left_label.grid(row=0, column=0)

        bottom_right_label = Label(self.master, text="I am at the bottom right")
        bottom_right_label.grid(row=2, column=2)

root = Tk()
Application(root)
root.mainloop()

What's the difference between fill and expand in pack geometry manager?

This has been asked a few times and here is a link to a Question/Answer on just that topic.

Here is a short answer related to that topic:

Essentially the fill option tells tkinter that you want to fill either the x axes or y axes of the space available to the widget or both directions. This means if a frame has a set size and you place a button in that frame with the fill = BOTH option then the button will fill the size of that frame and if that frame gets resized then the button will as well.

The expand option tells the manager to fill all available space between all widgets in a given frame/window. So they will share the space evenly if other widgets are also assigned the expand options. Keep in mind this is a simple explanation you should read up on the documentation to get the full picture.

when I create a = Text(root, width=100, height=100), then type a.pack(side=TOP) or a.pack(side=LEFT) or a.pack(side=RIGHT), why does the text box always sits in the bottom of the page?

The simple answer is that it doesn't.

If you are seeing this then it is caused by something else and not the way you have packed the widget.

Take a look at the below example code and play around with resizing the window. You will see how each pack option works.

from tkinter import *

class Application():
    def __init__(self, master):

        self.master = master
        self.master.geometry("400x400")
        Text(root, width=10, height=4).pack(side=TOP)
        Text(root, width=10, height=4).pack(side=LEFT)
        Text(root, width=10, height=4).pack(side=RIGHT)
        Text(root, width=10, height=4).pack(side=BOTTOM)


root = Tk()
Application(root)
root.mainloop()

Results:

enter image description here

Let me know if you have any more questions.

If anyone would like me to expand on any of my answer just let me know and I will add it.

Post a Comment for "Some Elementary Tkinter Questions"