1

I'm building a Python app using tkinter. It will be used to control my irrigation system. At the beginning I need to get the basic parameters of the control system including which days of the week each valve (up to 4) will run. At the beginning I have the following code that will get the days of the week for each valve. However, when I look at the code I see that I've repeated lots of the same stuff and wonder whether there's a way to put this stuff in a loop that will change for variable numbers of valves. Since I'm in the early stages of Python learning I'm not able to get this done (assuming it's possible). Maybe someone can suggest a way to get it done. Thanks in advance for any help!

def var_states():
   print(Valve1_1.get(), Valve1_2.get(), Valve1_3.get(), Valve1_4.get(), Valve1_5.get(), Valve1_6.get(), Valve1_7.get())
   print(Valve2_1.get(), Valve2_2.get(), Valve2_3.get(), Valve2_4.get(), Valve2_5.get(), Valve2_6.get(), Valve2_7.get())
   print(Valve3_1.get(), Valve3_2.get(), Valve3_3.get(), Valve3_4.get(), Valve3_5.get(), Valve3_6.get(), Valve3_7.get())
   print(Valve4_1.get(), Valve4_2.get(), Valve4_3.get(), Valve4_4.get(), Valve4_5.get(), Valve4_6.get(), Valve4_7.get())

main_title = Label(root, text="Main")
main_title.grid(row=0, column=0)

######################################################################################
#Get days when system will run for Valve 1
######################################################################################
labelValve1 = Label(root, text='Valve 1')
labelValve1.grid(column = 0, row = 1, ipadx=10, ipady=10)
Valve1_1=IntVar()
Checkbutton(root, text="Sunday", variable=Valve1_1).grid(row=1, column=1)
Valve1_2=IntVar()
Checkbutton(root, text="Monday", variable=Valve1_2).grid(row=1, column=2)
Valve1_3=IntVar()
Checkbutton(root, text="Tuesday", variable=Valve1_3).grid(row=1, column=3)
Valve1_4=IntVar()
Checkbutton(root, text="Wednesday", variable=Valve1_4).grid(row=1, column=4)
Valve1_5=IntVar()
Checkbutton(root, text="Thursday", variable=Valve1_5).grid(row=1, column=5)
Valve1_6=IntVar()
Checkbutton(root, text="Friday", variable=Valve1_6).grid(row=1, column=6)
Valve1_7=IntVar()
Checkbutton(root, text="Saturday", variable=Valve1_7).grid(row=1, column=7)
######################################################################################

######################################################################################
#Get days when system will run for Valve 2
######################################################################################
labelValve2 = Label(root, text='Valve 2')
labelValve2.grid(column = 0, row = 2, ipadx=10, ipady=10)
Valve2_1=IntVar()
Checkbutton(root, text="Sunday", variable=Valve2_1).grid(row=2, column=1)
Valve2_2=IntVar()
Checkbutton(root, text="Monday", variable=Valve2_2).grid(row=2, column=2)
Valve2_3=IntVar()
Checkbutton(root, text="Tuesday", variable=Valve2_3).grid(row=2, column=3)
Valve2_4=IntVar()
Checkbutton(root, text="Wednesday", variable=Valve2_4).grid(row=2, column=4)
Valve2_5=IntVar()
Checkbutton(root, text="Thursday", variable=Valve2_5).grid(row=2, column=5)
Valve2_6=IntVar()
Checkbutton(root, text="Friday", variable=Valve2_6).grid(row=2, column=6)
Valve2_7=IntVar()
Checkbutton(root, text="Saturday", variable=Valve2_7).grid(row=2, column=7)
######################################################################################

######################################################################################
#Get days when system will run for Valve 3
######################################################################################
labelValve3 = Label(root, text='Valve 3')
labelValve3.grid(column = 0, row = 3, ipadx=10, ipady=10)
Valve3_1=IntVar()
Checkbutton(root, text="Sunday", variable=Valve3_1).grid(row=3, column=1)
Valve3_2=IntVar()
Checkbutton(root, text="Monday", variable=Valve3_2).grid(row=3, column=2)
Valve3_3=IntVar()
Checkbutton(root, text="Tuesday", variable=Valve3_3).grid(row=3, column=3)
Valve3_4=IntVar()
Checkbutton(root, text="Wednesday", variable=Valve3_4).grid(row=3, column=4)
Valve3_5=IntVar()
Checkbutton(root, text="Thursday", variable=Valve3_5).grid(row=3, column=5)
Valve3_6=IntVar()
Checkbutton(root, text="Friday", variable=Valve3_6).grid(row=3, column=6)
Valve3_7=IntVar()
Checkbutton(root, text="Saturday", variable=Valve3_7).grid(row=3, column=7)
######################################################################################

######################################################################################
#Get days when system will run for Valve 4
######################################################################################
labelValve4 = Label(root, text='Valve 2')
labelValve4.grid(column = 0, row = 4, ipadx=10, ipady=10)
Valve4_1=IntVar()
Checkbutton(root, text="Sunday", variable=Valve4_1).grid(row=4, column=1)
Valve4_2=IntVar()
Checkbutton(root, text="Monday", variable=Valve4_2).grid(row=4, column=2)
Valve4_3=IntVar()
Checkbutton(root, text="Tuesday", variable=Valve4_3).grid(row=4, column=3)
Valve4_4=IntVar()
Checkbutton(root, text="Wednesday", variable=Valve4_4).grid(row=4, column=4)
Valve4_5=IntVar()
Checkbutton(root, text="Thursday", variable=Valve4_5).grid(row=4, column=5)
Valve4_6=IntVar()
Checkbutton(root, text="Friday", variable=Valve4_6).grid(row=4, column=6)
Valve4_7=IntVar()
Checkbutton(root, text="Saturday", variable=Valve4_7).grid(row=4, column=7)
######################################################################################

Button(root, text='Enter days of the week for all valves', command=var_states).grid(column=0, row=6, sticky=W, pady=4)

dwburger
  • 51
  • 1
  • 6
  • 1
    Create a [custom widget](https://stackoverflow.com/a/30489525/3962537) for one valve (i.e. encompassing one of those 4 big repeated blocks). Then refactor that using lists and loops to further reduce repetition. Similarly use a list and loop to have 4 instances of your custom widget. – Dan Mašek Dec 05 '22 at 19:02

1 Answers1

1

You can use a loop, and store the variables and/or widgets in a dictionary.

vars = {}
for (i, day) in enumerate(
    ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
):
    vars[day] = tk.IntVar()
    cb = tk.Checkbutton(root, text=day, variable=vars[day])
    cb.grid(row=3, column=i + 1)

Take that concept and roll it into a custom class that represents a single valve. You can then create an instance of each valve and store them in a list.

It might look something like this:

import tkinter as tk

root = tk.Tk()

class Valve(tk.Frame):
    def __init__(self, parent, label):
        super().__init__(parent)

        self.label = label
        self.vars = {}

        label = tk.Label(self, text=label, anchor="w")
        label.grid(row=0, column=0, sticky="ew")

        for (i, day) in enumerate(
            ("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")
        ):
            self.vars[day] = tk.IntVar()
            cb = tk.Checkbutton(self, text=day, variable=self.vars[day])
            cb.grid(row=0, column=i + 1)

    def get_days(self):
        result = []
        for day in (
                "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
        ):
            if self.vars[day].get() == 1:
                result.append(day)
        return ",".join(result)

valves = []
for i in range(4):
    valve = Valve(root, label=f"Valve {i+1}")
    valves.append(valve)
    valve.pack(side="top", fill="x")

def print_days():
    for valve in valves:
        print(f"{valve.label}: {valve.get_days()}")

button = tk.Button(root, text="Print Days", command=print_days)
button.pack()

root.mainloop()
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Wow...thanks for that! I don't understand everything that's in there, but I will! Thanks again! – dwburger Dec 05 '22 at 19:36
  • Maybe eliminate that repeated tuple of day names as well? :) – Dan Mašek Dec 05 '22 at 19:42
  • @DanMašek: oh, sure, there are definitely some optimizations that can be made in this code. The idea was to expose the concept, not create production-ready code. – Bryan Oakley Dec 05 '22 at 19:47
  • @Bryan Oakley: I've been able to understand what you did here. However, what I'd like to do is store the data to a file that results from the "print_days()" function. I'm not sure what to look for and have been spinning my wheels for a day. Maybe you can point me in the right direction??? Thanks! – dwburger Dec 08 '22 at 19:05
  • Never mind...I figured it out. Once I created an empty dictionary, I used the following statements to create the dictionary and save it to disk. Thanks! ``` valveDict[valve.label] = valve.get_days() f.write(str(valveDict)) ``` – dwburger Dec 09 '22 at 15:46