Home > Net >  Update dictionary values using tkinter entries via bind method
Update dictionary values using tkinter entries via bind method

Time:10-27

Tkinter-based GUI that is supposed to update the dictionary values. It works fine, there are still two issues:

  1. in order to update the entry value I used the bind method, i.e. object.bind("<Key>", self._accept), it works only with the Enter key, with the other keys it prints the previous value inserted in the entry [SOLVED]
  2. I can't figure out how to set entry_c2=entry_c1 when the corresponding checkbox is deactivated.
import tkinter as tk

def create_input_dictionary():
    out = {'Header': ['LLL', 'Min', 'Max'],
           'Do': ['l1', 'mm', '25', '35'],
           'Di': ['l2', 'mm', '19', '29'],
           'tt': ['l3', 'mm', '0.8', '1.2'],
           'y': ['l4', '-', '2', '3'],
           'eps': ['l5', 'mm', '0.1', '0.2'],
           'Header': ['LLL', 'Min', 'Max'],
           'P': ['l6', 'MPa', '3', '5'],
           'T': ['l7', '°C', '30', '50'],
           'V': ['l8', 'm/s', '3', '5'],
           'nos': ['l10', '10']
           }
    return out

def isfloat(value):
    """The function checks if an element is a number"""
    try:
        float(value)
        return True
    except ValueError:
        return False

def isinteger(value):
    """The function checks if an element is a number"""
    try:
        int(value)
        return True
    except ValueError:
        return False

def isnumber(value):
    return isfloat(value) or isinteger(value)

def allarefloats(var_list):
    """The function checks if all the elements in the lists are numbers"""
    check = True
    for item in var_list:
        check = check and isfloat(item)
    return check

def allareinteger(var_list):
    """The function checks if all the elements in the lists are numbers"""
    check = True
    for item in var_list:
        check = check and isinteger(item)
    return check

def areallnumbers(var_list):
    check = True
    for item in var_list:
        check = check and (isfloat(item) or isinteger(item))
    return check

class DictionaryEntry(tk.Frame):
    """get entry and update dictionary values"""

    def __init__(self, parent, key_dict, values_dict, row_entry, bg=None, **kwargs):
        if bg is None:
            bg = parent['bg']
        super().__init__(parent, bg=bg, **kwargs)

        self.row = row_entry
        self.key = key_dict
        self.values = values_dict
        self.nac = tk.IntVar()
        self.entry_c1 = None
        self.entry_c2 = None

        if isnumber(self.values[-1]):
            if isnumber(self.values[-2]):

                self.variable = tk.StringVar(value=self.values[-2]), tk.StringVar(self, self.values[-1])

                tk.Checkbutton(parent, variable=self.nac, command=lambda: self.naccheck()).grid(row=self.row, column=0,
                                                                                                sticky='ns')

                label = self.values[0]   ' ('   self.values[1]   ') '
                tk.Label(parent, text=label, padx=10, pady=5).grid(row=self.row, column=1, sticky='nw')

                self.entry_c1 = tk.Entry(parent, textvariable=self.variable[0], width=10, state='normal')
                self.entry_c1.grid(row=self.row, column=2)

                self.entry_c2 = tk.Entry(parent, textvariable=self.variable[1], width=10, state='disabled')
                self.entry_c2.grid(row=self.row, column=3)

            else:
                self.variable = tk.StringVar(self, value=self.values[-1])

                tk.Label(parent, text='SIMULATION PARAMETERS', padx=10, pady=5).grid(row=self.row, columnspan=4,
                                                                                     sticky='ns')
                tk.Label(parent, text=self.values[0], padx=10, pady=5).grid(row=self.row   1, columnspan=2, sticky='ns')
                self.variable = tk.StringVar(self, self.values[-1])
                self.entry_c1 = tk.Entry(parent, textvariable=self.variable, width=10, state='normal')
                self.entry_c1.grid(row=self.row   1, column=2, columnspan=2)

            self.entry_c1.bind("<Key>", self._accept)
            if self.entry_c2 is not None:
                self.entry_c2.bind("<Key>", self._accept)

        else:
            tk.Label(parent, text=self.values[0], padx=10, pady=5).grid(row=self.row, column=1, sticky='ns')
            tk.Label(parent, text=self.values[1], padx=10, pady=5).grid(row=self.row, column=2, sticky='ns')
            tk.Label(parent, text=self.values[2], padx=10, pady=5).grid(row=self.row, column=3, sticky='ns')

        print(self.entry_c1, self.entry_c2)

    def naccheck(self):
        if self.nac.get() == 0:
            self.entry_c2.configure(state='disabled')
        else:
            self.entry_c2.configure(state='normal')

    def _accept(self, event):  # finire!! update dictionary
        """Accept value change when return is pressed or losing focus"""
        try:
            if self.entry_c1 is not None:
                self.values[-2] = self.entry_c1.get()
            if self.entry_c2 is not None:
                self.values[-1] = self.entry_c2.get()

        except ValueError:
            pass

if __name__ == '__main__':

    dictionary = create_input_dictionary()

    root = tk.Tk()
    radio_button_frame = tk.Frame(root, padx=10, pady=5)
    input_data_frame = tk.Frame(root, padx=10, pady=5)
    simul_button_frame = tk.Frame(root, padx=10, pady=5)

    # place the container within the main window using grid
    radio_button_frame.grid(row=0, column=0, sticky='ns')
    input_data_frame.grid(row=1, column=0, sticky='ns')
    simul_button_frame.grid(row=2, column=0, sticky='ns')

    row = 0
    for key, values in dictionary.items():
        obj = DictionaryEntry(input_data_frame, key, values, row)
        dictionary.update({key: obj.values})
        row  = 1
    tk.Button(simul_button_frame, text="click me", command=lambda: print(dictionary)).pack(padx=10, pady=5)

    root.update()
    root.mainloop()

EDIT: First point marked as fixed

CodePudding user response:

For item 1, just bind <KeyRelease> instead of <Key>.

For item 2, just copy the content from entry_c1 to entry_c2 before disabling entry_c2 inside naccheck():

    def naccheck(self):
        if self.nac.get() == 0:
            # copy value from entry_c1 to entry_c2
            value = self.variable[0].get()
            self.variable[1].set(value)
            # update self.values[-1] as well
            self.values[-1] = value
            # then disable entry_c2
            self.entry_c2.configure(state='disabled')
        else:
            self.entry_c2.configure(state='normal')
  • Related