1

I program a GUI in Python3 with Tkinter and place widgets with .grid(). How can i tell Tkinter to place a new widget on the same row as the last placed widget but on a new, specified, column. The problem is that Tkinter automatically uses the next row when i don't specify the row and i don't want to hardcode the row number or pollute my code with a row counter that i have to increment every time i insert a widget in column 0.

What i tried:

#!/usr/bin/env python3
from tkinter import *
root=Tk()
Label(root, text="Label 0").grid(column=0)
Label(root, text="Label 1").grid(column=1)
Label(root, text="Label 2").grid(column=0)
Label(root, text="Label 3").grid(column=1)
Label(root, text="Label 4").grid(column=0)
Label(root, text="Label 5").grid(column=1)
root.mainloop()

How the layout looks like

Label 0
        Label 1
Label 2
        Label 3
Label 3
        Label 5

How the layout should look like

Label 0 Label 1
Label 2 Label 3
Label 3 Label 5

What i don't want

It is possible to achieve the correct layout by specify the column number, like this:

#!/usr/bin/env python3
from tkinter import *
root=Tk()
Label(root, text="Label 0").grid(column=0,row=0)
Label(root, text="Label 1").grid(column=1,row=0)
Label(root, text="Label 2").grid(column=0,row=1)
Label(root, text="Label 3").grid(column=1,row=1)
Label(root, text="Label 4").grid(column=0,row=2)
Label(root, text="Label 5").grid(column=1,row=2)
root.mainloop()

But that is not flexible and inserting something in the second row means the code for all following rows have to be changed. Adding a row counter is possible, but this is error prone since it is easy to forget to increase the counter. Is there a way to insert a new widget on the second column on the same row as the last inserted widget without hardcoding or keep track of the last row number?

Or is there a function that returns the row of the last inserted widget? So that i can do this:

#!/usr/bin/env python3
from tkinter import *
root=Tk()
Label(root, text="Label 0").grid(column=0)
Label(root, text="Label 1").grid(column=1,row=<root.unknowFunctionToGetTheLastInsertedRow>)
Label(root, text="Label 2").grid(column=0)
Label(root, text="Label 3").grid(column=1,row=<root.unknowFunctionToGetTheLastInsertedRow>)
Label(root, text="Label 4").grid(column=0)
Label(root, text="Label 5").grid(column=1,row=<root.unknowFunctionToGetTheLastInsertedRow>)
root.mainloop() 

1 Answers1

2

I took a look at the documentation for the underlying Tk grid command, and it's vastly more convenient to use than the provided Python wrapper, since you can call it on multiple widgets at once (in which case they're given successive column numbers in a new row). You'd hardly ever need to supply an explicit row or column number. Here's an example of how you could use grid in this style from Python:

from tkinter import *
root=Tk()
root.tk.call('grid',
    Label(root, text="Label 0"),
    Label(root, text="Label 1")
)
root.tk.call('grid',
    Label(root, text="Label 2"),
    Label(root, text="Label 3")
)
root.tk.call('grid',
    Label(root, text="Label 4"),
    Label(root, text="Label 5")
)
root.mainloop() 

enter image description here

Other options you can pass to grid when used in this manner: "x" to leave a grid cell empty, "-" to increase columnspan of the widget to the left, "^" to increase rowspan of the widget above.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
  • While I think you're right that the underlying `grid` command is more powerful than the python wrapper, your example seems very confusing. You're showing each column as a row which makes it very hard to visualize the layout by looking at the code. It would look better if the items which were side-by-side visually were also side-by-side in the code. – Bryan Oakley Mar 17 '21 at 17:40
  • @BryanOakley, I see your point, but I'd think that most real-world widgets are going to have enough options specified that you wouldn't be able to fit more than one on a line. – jasonharper Mar 17 '21 at 17:44