-1

I'm learning how to use tkinter, and some example code to create a bunch of buttons for a calculator is used. It seems very bulky and repetitive, so I was wondering if there was a way to assign some or all of the parameters to a single object and just modify and pass that each time?

button1 = Button(gui, text=' 1 ', fg='black', bg='red',
                command=lambda: press(1), height=1, width=7)
button1.grid(row=2, column=0)

button2 = Button(gui, text=' 2 ', fg='black', bg='red',
                command=lambda: press(2), height=1, width=7)
button2.grid(row=2, column=1)

button3 = Button(gui, text=' 3 ', fg='black', bg='red',
                command=lambda: press(3), height=1, width=7)
button3.grid(row=2, column=2)

button4 = Button(gui, text=' 4 ', fg='black', bg='red',
                command=lambda: press(4), height=1, width=7)
button4.grid(row=3, column=0)

button5 = Button(gui, text=' 5 ', fg='black', bg='red',
                command=lambda: press(5), height=1, width=7)
button5.grid(row=3, column=1)

button6 = Button(gui, text=' 6 ', fg='black', bg='red',
                command=lambda: press(6), height=1, width=7)
button6.grid(row=3, column=2)

button7 = Button(gui, text=' 7 ', fg='black', bg='red',
                command=lambda: press(7), height=1, width=7)
button7.grid(row=4, column=0)

button8 = Button(gui, text=' 8 ', fg='black', bg='red',
                command=lambda: press(8), height=1, width=7)
button8.grid(row=4, column=1)

button9 = Button(gui, text=' 9 ', fg='black', bg='red',
                command=lambda: press(9), height=1, width=7)
button9.grid(row=4, column=2)

button0 = Button(gui, text=' 0 ', fg='black', bg='red',
                command=lambda: press(0), height=1, width=7)
button0.grid(row=5, column=0)
martineau
  • 119,623
  • 25
  • 170
  • 301

1 Answers1

1

In order to to keep your code DRY and avoid repeating yourself— which is essentially what you're asking I think — you need to create the Buttons in a loop. However dynamically creating Python variables is generally not a good idea, so they should instead be put in some kind of container, like a list, rather than trying to give each of them individual names.

I'm not sure exactly if that is what you meant by "assign some or all of the parameters to a single object" because tkinter it could also mean grouping the widget together in some kind of GUI container. tkinter has something called a Frame widget for that sort of thing which allows them to be treated as a group.

The sample code below does both — it creates a buttons list and a button_frame:

import tkinter as tk  # PEP 8 suggests avoiding `import *`.

NUM_BUTTONS = 10
BUTTONS_PER_ROW = 3

gui = tk.Tk()

def press(digit):
    gui.bell()

button_frame = tk.Frame(gui)  # Parent frame to hold all button widgets.
button_frame.pack()

buttons = []  # List of button widgets.
start_row = 2
for i in range(NUM_BUTTONS):
    row, col = divmod(i, BUTTONS_PER_ROW)
    value = (i+1) % NUM_BUTTONS
    button = tk.Button(button_frame, text=f'{value}', fg='black', bg='red',
                       command=lambda digit=value: press(digit), height=1, width=7)
    button.grid(row=start_row+row, column=col)
    buttons.append(button)  # Add widget to list.

gui.mainloop()

Here's the on-screen result:

Screenshot

martineau
  • 119,623
  • 25
  • 170
  • 301
  • You forgot to store the created buttons into the list `buttons`. – acw1668 Feb 15 '22 at 09:52
  • @acw1668: Thanks for pointing that out. Coincidentally I was already here fixing a different bug I noticed myself. – martineau Feb 15 '22 at 10:07
  • Just for curiosity, why do you use `:2d` to format the single digit value? Since you have used `width=7`, the formatting is not necessary. – acw1668 Feb 15 '22 at 10:25
  • @acw1668: I was thinking I needed to do it because the default justification of button text is `tk.CENTER`, but realized after your comment that it doesn't matter — so have removed it. – martineau Feb 15 '22 at 11:17