Home > OS >  Address multiple widgets in a for loop in Tkinter
Address multiple widgets in a for loop in Tkinter

Time:04-28

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 :)

  • Related