I need a way to address multiple widgets in TKinter like labels, entries or scales in a for loop and edit them afterwards. It is part of a bigger GUI and without a solution, the code will be way too long and confusing. The following example should explain the problem.
import tkinter as tk
import tkinter.ttk as ttk
class NewprojectApp:
def __init__(self, master=None):
# build the GUI
self.frame1 = ttk.Frame(master)
self.scale1 = tk.Scale(self.frame1)
self.scale1.configure(label="scale2", orient="horizontal")
self.scale1.grid(column="0", row="1")
self.scale2 = tk.Scale(self.frame1)
self.scale2.configure(label="scale3", orient="horizontal")
self.scale2.grid(column="0", row="2")
self.scale3 = tk.Scale(self.frame1)
self.scale3.configure(label="scale4", orient="horizontal")
self.scale3.grid(column="0", row="3")
self.button1 = ttk.Button(self.frame1)
self.button1.configure(text="set default value")
self.button1.grid(column="0", pady="5", row="4")
self.button1.configure(command=self.set_value)
self.frame1.configure(height="200", width="200")
self.frame1.grid(column="0", row="0")
# Main widget
self.mainwindow = self.frame1
def run(self):
self.mainwindow.mainloop()
def set_value(self):
# set the value of multiples scales to a new value
self.scale1.set(20)
self.scale2.set(20)
self.scale3.set(20)
"""
I want to change functions like the one above into for loops;
The following is something I tried out but that didn't work
for i in range(1,3):
current_scale = 'self.scale' str(i)
current_scale.set(20)
"""
if __name__ == "__main__":
root = tk.Tk()
app = NewprojectApp(root)
app.run()
Thank you so much in advance!
CodePudding user response:
There are different options for what you're trying to achieve.
To keep your for
loop, you could do something like this:
def set_value(self):
for i in range(1, 4):
getattr(self, f'scale{i}').set(20)
in this way, you are correctly using i
as a variable to address the widget. Obviously, you should take care of addressing the correct widget (e.g. set a default
for getattr
, or use a try
, or ensure that hasattr(self, scale{i})
)
Another approach could be to iterate on the elements of self
, running set
when appropriate:
def set_value(self):
for widget_name in dir(self):
widget = getattr(self, widget_name)
if isinstance(widget, tk.Scale): # ensure widget is of Scale class
widget.set(20)
Finally, you could simply define a list of widgets you want to iterate on:
class NewprojectApp:
def __init__(self, master=None):
# build the GUI
self.frame1 = ttk.Frame(master)
self.button1 = ttk.Button(self.frame1)
self.button1.configure(text="set default value")
self.button1.grid(column="0", pady="5", row="4")
self.button1.configure(command=self.set_value)
self.frame1.configure(height="200", width="200")
self.frame1.grid(column="0", row="0")
# Define your scales
self.scales = []
for i in range(1, 4):
self.scales.append(tk.Scale(self.frame1))
self.scales[-1].configure(label=f"scale{i}", orient="horizontal")
self.scales[-1].grid(column=0, row=i)
# You could also initiate your scales indipendently and then do:
# self.scales = [scale1, scale2, scale3]
# Main widget
self.mainwindow = self.frame1
def run(self):
self.mainwindow.mainloop()
def set_value(self):
for scale in self.scales:
scale.set(20)
in this case you must pay attention when you want to address a single scale. You could also keep both self.scale{i}
and self.scales
.
There are probably many other ways to achieve the result, but you may start from here and find what suits you best :)