I want to add 10 buttons to Tkinter, named One to Ten. I basically just used the brute force method, adding each button as I went, in the init function of my application's class. It works, but I want to minimize the code used, to be more efficient, such as using a data structure to hold all the buttons.
I was thinking of using a buttonBox
to hold all the buttons in, but I was not sure if I could manipulate the placement via grid()
to place the buttons how I wanted.
self.one = Button(frame, text="One", command=self.callback)
self.one.grid(sticky=W+E+N+S, padx=1, pady=1)
self.two = Button(frame, text="Two", command=self.callback)
self.two.grid(sticky=W+E+N+S, row=0, column=1, padx=1, pady=1)
self.three = Button(frame, text="Three", command=self.callback)
self.three.grid(sticky=W+E+N+S, row=0, column=2, padx=1, pady=1)
# ...
self.ten = Button(frame, text="Ten", command=self.callback)
self.ten.grid(sticky=W+E+N+S, row=1, column=4, padx=1, pady=1)
Can anyone show me a way to make this more efficient, such as a data structure?
We can perform a certain action with the help of a Button that encapsulates the function and the objects. However, there might be cases when we want to perform multiple operations with a single button. This can be achieved by defining the lambda functions which target multiple events or callback in the application.
The button in the tkinter module can be placed or move to any position in two ways: By using the place() method. And by using the pack() method.
The frame is a widget or container which used to handle the tkinter GUI. Frist, we will create the main frame or parent frame, inside it, we have created nested frames. When we need to devided the window more than two or three parts then we will use the concept of Frame.
You can use canvas to draw different shapes, arcs, and objects to animate within the canvas. To create a button on a Tkinter Canvas, simply pass the parent as the canvas in place of a parent in the Button constructor.
Instead of naming the buttons self.one
, self.two
, etc., it would be more convenient to refer to them by indexing a list, such as self.button
.
If the buttons do different things, then you just have to explicitly associate buttons with callbacks. For example:
name_callbacks=(('One',self.callback_one),
('Two',self.callback_two),
...,
('Ten',self.callback_ten))
self.button=[]
for i,(name,callback) in enumerate(name_callbacks):
self.button.append(Button(frame, text=name, command=callback))
row,col=divmod(i,5)
self.button[i].grid(sticky=W+E+N+S, row=row, column=col, padx=1, pady=1)
If the buttons all do similar things, then one callback may suffice to service them all. Since the callback itself can't take arguments, you can setup a callback factory to pass the arguments in through a closure:
def callback(self,i): # This is the callback factory. Calling it returns a function.
def _callback():
print(i) # i tells you which button has been pressed.
return _callback
def __init__(self):
names=('One','Two','Three','Four','Five','Six','Seven','Eight','Nine','Ten')
self.button=[]
for i,name in enumerate(names):
self.button.append(Button(frame, text=name, command=self.callback(i+1)))
row,col=divmod(i,5)
self.button[i].grid(sticky=W+E+N+S, row=row, column=col, padx=1, pady=1)
You could put all the buttons properties in a dict, and then loop on it to create your buttons, here is an example:
buttons = {
'one': {'sticky': W+E+N+S, 'padx': 1, 'pady': 1},
'two': {'sticky': W+E+N+S, 'row': 0, 'column': 1, 'padx': 1, 'pady': 1},
'three': {'sticky': W+E+N+S, 'row': 0, 'column': 2, 'padx': 1, 'pady': 1}
}
for b in buttons:
button = Button(frame, text=b.title(), command=self.callback)
button.grid(**buttons[b])
setattr(self, b, button)
This would also allow you to easily add new buttons if needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With