Search code examples
pythontkintertkinter-entrytkinter-label

Reduce the lines of code (tkinter, Python, Multiple labels, entry)


Explanation: On Clicking submit button, the entries should appear in tree.

I have restricted the entries fields so they can take only two values (using trace method).

Problem 1: I have a total of 8 entries, which means the code has 8 StringVar, 8 entry, 8 label, 1 button and a total of 17 grids. Please help me to reduce the code.

Problem 2: I need entries in one list which I can use globally.

from tkinter import Tk, Frame, Button, Label, Entry, ttk, StringVar, Scrollbar
import datetime

# Main Window
class WINDOW(Tk):
    def __init__(self, master):
        Tk.__init__(self, master)
        self.master = master

        frame1 = Frame1(self)
        frame1.grid(row=0,column=0)
        list_of_entries=[]

class Frame1(Frame):
    def __init__(self, master):
        Frame.__init__(self, master,height=master.winfo_screenheight(),
                       width=master.winfo_screenwidth())
        self.master = master


        one_var = StringVar()
        two_var = StringVar()
        three_var = StringVar()
        four_var = StringVar()
        five_var = StringVar()

        # Restrict entry field for 2 values only (using trace)
        one_var.trace("w", lambda name, index, mode, one_var=one_var: callback())
        two_var.trace("w", lambda name, index, mode, two_var=one_var: callback())
        three_var.trace("w", lambda name, index, mode, three_var=one_var: callback())
        four_var.trace("w", lambda name, index, mode, four_var=one_var: callback())
        five_var.trace("w", lambda name, index, mode, five_var=one_var: callback())

        def callback(*args):
            one_var.set(one_var.get()[:2])
            two_var.set(two_var.get()[:2])
            three_var.set(three_var.get()[:2])
            four_var.set(four_var.get()[:2])
            five_var.set(five_var.get()[:2])


        # Request frame labels

        DATA0_lbl = Label(self, text='DATA0', font=('calibre', 10, 'bold'))
        DATA1_lbl = Label(self, text='DATA1', font=('calibre', 10, 'bold'))
        DATA2_lbl = Label(self, text='DATA2', font=('calibre', 10, 'bold'))
        DATA3_lbl = Label(self, text='DATA3', font=('calibre', 10, 'bold'))
        DATA4_lbl = Label(self, text='DATA4', font=('calibre', 10, 'bold'))

        # Request frame label grid
        DATA0_lbl.grid(row=0, column=0)
        DATA1_lbl.grid(row=0, column=1)
        DATA2_lbl.grid(row=0, column=2)
        DATA3_lbl.grid(row=0, column=3)
        DATA4_lbl.grid(row=0, column=4)

        # Request frame entry fields
        DATA0_entry = Entry(self,textvariable=one_var, width=10, font=('calibre', 10, 'normal'))
        DATA1_entry = Entry(self,textvariable=two_var,  width=10, font=('calibre', 10, 'normal'))
        DATA2_entry = Entry(self, textvariable=three_var, width=10, font=('calibre', 10, 'normal'))
        DATA3_entry = Entry(self,textvariable=four_var,  width=10, font=('calibre', 10, 'normal'))
        DATA4_entry = Entry(self, textvariable=five_var, width=10, font=('calibre', 10, 'normal'))

        # Request frame entry field grid
        DATA0_entry.grid(row=1, column=0)
        DATA1_entry.grid(row=1, column=1)
        DATA2_entry.grid(row=1, column=2)
        DATA3_entry.grid(row=1, column=3)
        DATA4_entry.grid(row=1, column=4)



        # Log data sheet
        NewTree = ttk.Treeview(self, height=23, columns=("DATA0","DATA1", "DATA2", "DATA3","DATA4"))

        NewTree.column("#0", width=180)
        NewTree.column("#1", width=150)
        NewTree.column("#2", width=150)
        NewTree.column("#3", width=150)
        NewTree.column("#4", width=150)
        NewTree.column("#5", width=150)

        NewTree.heading("#0",text='TIME')
        NewTree.heading("#1",text='DATA0')
        NewTree.heading("#2",text='DATA1')
        NewTree.heading("#3",text='DATA2')
        NewTree.heading("#4",text="DATA3")
        NewTree.heading("#5", text="DATA4")

        NewTree.grid(row=5, columnspan=4)

        def insert_data():
            NewTree.insert('', 'end', text=datetime.datetime.now(),
                                 values=(DATA0_entry.get(),
                                         DATA1_entry.get(),
                                         DATA2_entry.get(),
                                         DATA3_entry.get(),
                                         DATA4_entry.get()))
            one_var.set("")
            two_var.set("")
            three_var.set("")
            four_var.set("")
            five_var.set("")

        submit_button = Button(self, text="SUBMIT", command=insert_data)
        submit_button.grid(row=3, column=4)


root = WINDOW(None)
root.geometry(f'{root.winfo_screenwidth()}x{root.winfo_screenheight()}')
root.title("ADD DATA")


root.mainloop()

Solution

  • You can use a loop to create the entries and labels. By using the validation feature of the entry widgets rather than the trace, you can throw away the trace statements and the instances of StringVar completely.

    All combined, this will end up reducing the code by about 50 lines or so.

    For a detailed explanation of entry validation, see Interactively validating Entry widget content in tkinter

    Here's a complete example:

    from tkinter import Tk, Frame, Button, Label, Entry, ttk, StringVar, Scrollbar
    import datetime
    
    # Main Window
    class WINDOW(Tk):
        def __init__(self, master):
            Tk.__init__(self, master)
            self.master = master
    
            frame1 = Frame1(self)
            frame1.grid(row=0,column=0)
            list_of_entries=[]
    
    class Frame1(Frame):
        def __init__(self, master):
            Frame.__init__(self, master,height=master.winfo_screenheight(),
                           width=master.winfo_screenwidth())
            self.master = master
    
            vcmd = (self.register(self.validate), '%P')
            self.entries = []
            for i in range(5):
                label = Label(self, text=f"DATA{i}", font=('calibre', 10, 'bold'))
                entry = Entry(self, validatecommand=vcmd, validate='key', width=10, font=('calibre', 10, 'normal'))
                label.grid(row=0, column=i)
                entry.grid(row=1, column=i)
                self.entries.append(entry)
    
            # Log data sheet
            NewTree = ttk.Treeview(self, height=23, columns=("DATA0","DATA1", "DATA2", "DATA3","DATA4"))
    
            NewTree.column("#0", width=180)
            NewTree.column("#1", width=150)
            NewTree.column("#2", width=150)
            NewTree.column("#3", width=150)
            NewTree.column("#4", width=150)
            NewTree.column("#5", width=150)
    
            NewTree.heading("#0",text='TIME')
            NewTree.heading("#1",text='DATA0')
            NewTree.heading("#2",text='DATA1')
            NewTree.heading("#3",text='DATA2')
            NewTree.heading("#4",text="DATA3")
            NewTree.heading("#5", text="DATA4")
    
            NewTree.grid(row=5, columnspan=4)
    
            def insert_data():
                NewTree.insert('', 'end', text=datetime.datetime.now(),
                                     values=(self.entries[0].get(),
                                             self.entries[1].get(),
                                             self.entries[2].get(),
                                             self.entries[3].get(),
                                             self.entries[4].get()))
                for i in range(5):
                    self.entries[i].delete(0, 'end')
    
            submit_button = Button(self, text="SUBMIT", command=insert_data)
            submit_button.grid(row=3, column=4)
    
        def validate(self, new_value):
            return len(new_value) <= 2
    
    
    root = WINDOW(None)
    root.geometry(f'{root.winfo_screenwidth()}x{root.winfo_screenheight()}')
    root.title("ADD DATA")
    
    
    root.mainloop()