An easier way to place multiple Tkinter buttons/labels?

Question:

This is my code and I was wondering if there if a more efficient way to write this grid

from tkinter import *

def btnClickFunction():
    print('clicked')

main = Tk()
main.geometry('745x435')
main.title('m')


Button(main, text='O', command=btnClickFunction).place(x=80, y=110)
Button(main, text='O', command=btnClickFunction).place(x=80, y=140)
Button(main, text='O', command=btnClickFunction).place(x=80, y=170)
Button(main, text='O', command=btnClickFunction).place(x=80, y=200)
Button(main, text='O', command=btnClickFunction).place(x=80, y=230)
Button(main, text='O', command=btnClickFunction).place(x=80, y=260)
Button(main, text='O', command=btnClickFunction).place(x=80, y=290)

Button(main, text='O', command=btnClickFunction).place(x=105, y=110)
Button(main, text='O', command=btnClickFunction).place(x=105, y=140)
Button(main, text='O', command=btnClickFunction).place(x=105, y=170)
Button(main, text='O', command=btnClickFunction).place(x=105, y=200)
Button(main, text='O', command=btnClickFunction).place(x=105, y=230)
Button(main, text='O', command=btnClickFunction).place(x=105, y=260)
Button(main, text='O', command=btnClickFunction).place(x=105, y=290)

Button(main, text='O', command=btnClickFunction).place(x=130, y=110)
Button(main, text='O', command=btnClickFunction).place(x=130, y=140)
Button(main, text='O', command=btnClickFunction).place(x=130, y=170)
Button(main, text='O', command=btnClickFunction).place(x=130, y=200)
Button(main, text='O', command=btnClickFunction).place(x=130, y=230)
Button(main, text='O', command=btnClickFunction).place(x=130, y=260)
Button(main, text='O', command=btnClickFunction).place(x=130, y=290)

Button(main, text='O', command=btnClickFunction).place(x=155, y=110)
Button(main, text='O', command=btnClickFunction).place(x=155, y=140)
Button(main, text='O', command=btnClickFunction).place(x=155, y=170)
Button(main, text='O', command=btnClickFunction).place(x=155, y=200)
Button(main, text='O', command=btnClickFunction).place(x=155, y=230)
Button(main, text='O', command=btnClickFunction).place(x=155, y=260)
Button(main, text='O', command=btnClickFunction).place(x=155, y=290)

Button(main, text='O', command=btnClickFunction).place(x=180, y=110)
Button(main, text='O', command=btnClickFunction).place(x=180, y=140)
Button(main, text='O', command=btnClickFunction).place(x=180, y=170)
Button(main, text='O', command=btnClickFunction).place(x=180, y=200)
Button(main, text='O', command=btnClickFunction).place(x=180, y=230)
Button(main, text='O', command=btnClickFunction).place(x=180, y=260)
Button(main, text='O', command=btnClickFunction).place(x=180, y=290)

Button(main, text='O', command=btnClickFunction).place(x=205, y=110)
Button(main, text='O', command=btnClickFunction).place(x=205, y=140)
Button(main, text='O', command=btnClickFunction).place(x=205, y=170)
Button(main, text='O', command=btnClickFunction).place(x=205, y=200)
Button(main, text='O', command=btnClickFunction).place(x=205, y=230)
Button(main, text='O', command=btnClickFunction).place(x=205, y=260)
Button(main, text='O', command=btnClickFunction).place(x=205, y=290)

Button(main, text='O', command=btnClickFunction).place(x=230, y=110)
Button(main, text='O', command=btnClickFunction).place(x=230, y=140)
Button(main, text='O', command=btnClickFunction).place(x=230, y=170)
Button(main, text='O', command=btnClickFunction).place(x=230, y=200)
Button(main, text='O', command=btnClickFunction).place(x=230, y=230)
Button(main, text='O', command=btnClickFunction).place(x=230, y=260)
Button(main, text='O', command=btnClickFunction).place(x=230, y=290)


Label(main, text='1').place(x=50, y=110)
Label(main, text='2').place(x=50, y=140)
Label(main, text='3').place(x=50, y=170)
Label(main, text='4').place(x=50, y=200)
Label(main, text='5').place(x=50, y=230)
Label(main, text='6').place(x=50, y=260)
Label(main, text='7').place(x=50, y=290)


Label(main, text='1').place(x=80, y=80)
Label(main, text='2').place(x=105, y=80)
Label(main, text='3').place(x=130, y=80)
Label(main, text='4').place(x=155, y=80)
Label(main, text='5').place(x=180, y=80)
Label(main, text='6').place(x=205, y=80)
Label(main, text='7').place(x=230, y=80)


main.mainloop()

Asked By: hhrymc

||

Answers:

The simple answer is to do so using loops. The x and y values seem to be linearly increasing so the code can be shortened by:

from tkinter import *

def btnClickFunction():
    print('clicked')

main = Tk()
main.geometry('745x435')
main.title('m')

#loop for placing all buttons
for i in range(80, 231, 25):
    for j in range(110, 291, 30):
        Button(main, text='O', command=btnClickFunction).place(x=i, y=j)

#loop for placing all vertical labels
for j in range(110, 291, 30):
    Label(main, text=str((j-110)//30+1)).place(x=50, y=j)

#loop for placing all horizontal labels
for i in range(80, 231, 25):
    Label(main, text=str((i-80)//25+1)).place(x=i, y=80)

main.mainloop()

Doing this using loops allows the size of the button matrix to be scalable by just changing the loop parameters. For generating the label text, a simple math equation is used which finds the number of times looped plus 1. To further improve this code, the ranges for x and y could be stored in variables so that increasing the size of the matrix would mean simply changing the variable values.

Answered By: cavalierDev

This is best handled with a nested for loop and the grid geometry manager. Notice how I’ve also offset the labels by one row / column so there’s nothing present at grid (0, 0)

import tkinter as tk  # it's best to avoid star imports!


# FYI: this should be 'btn_click_function' per Python style convention
def btn_click_function():  
    print('clicked')


main = tk.Tk()
main.geometry('745x435')
main.title('m')


for row in range(7):
    # row label
    r_lbl = tk.Label(main, text=row + 1)  # +1 to start numbering at 1 instead of 0
    r_lbl.grid(row=row + 1, column=0)
    for column in range(7):
        # column label
        c_lbl = tk.Label(main, text=column + 1)  # +1 to start numbering at 1...
        c_lbl.grid(row=0, column=column + 1)
        # button
        btn = tk.Button(main, command=btn_click_function, text='O')
        btn.grid(row=row + 1, column=column + 1)


if __name__ == '__main__':
    main.mainloop()

BTW: if you want space between the rows / columns or to change the size of the buttons, you can achieve this with the padx, pady, ipadx, and ipady args on each call to grid() – these will set the external x/y padding (space around the widget), and internal x/y padding (space inside the widget)

Answered By: JRiggles
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.