I am newbie to tkinter and OOP and I am trying to build a GUI that creates entries using a for loop. Basically it should:
- read a dictionary and use its keys as tk.Labels
- use its last two values as predefined values for the two tkinter entries (each label should have two antries).
- Each entry should have a checkbox that disable/enables the second entry for each row
- Use a button to update the dictionay's values
I have written the following modules:
import tkinter as tk
def create_input_dictionary():
out = {'Header 1': ['DATA', 'Min', 'Max'],
'Do': ['Lab1', 'mm', '25', '35'],
'Di': ['Lab1', 'mm', '25', '35'],
'nos': ['Lab9', '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 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
class gui:
'''this is a classe that creates an instance of the GUI'''
def __init__(self, master): # , container, input_dict): # , *args, **kwargs):
self.master = master
self.ck1 = []
self.ent1 = []
self.ent2 = []
def make_entry(self, container, input_dict):
self.container = container
self.input_dict = input_dict
self.entry_col1 = tk.StringVar()
self.entry_col2 = tk.StringVar()
self.label_entry = tk.StringVar()
self.nac = [tk.IntVar()] * len(input_dict)
for ind, key in enumerate(self.input_dict):
if 'Header' not in key:
n = 0
if key != 'nos':
self.ck1.append(tk.Checkbutton(self.container, variable=self.nac[n], command=lambda: self.naccheck()))
self.ck1[-1].grid(row=ind, column=0, sticky='ns')
n = 1
label = self.input_dict[key][0] '(' self.input_dict[key][1] ')'
tk.Label(self.container, text=label).grid(row=ind, column=1, sticky='nw')
self.ent1.append(
tk.Entry(self.container, width=10, background='white',
textvariable=self.entry_col1, state='normal'))
self.ent1[-1].grid(row=ind, column=2, sticky='ns')
self.ent2.append(tk.Entry(self.container, width=10, background='white',
textvariable=self.entry_col2, state='disabled'))
self.ent2[-1].grid(row=ind, column=3, sticky='ns')
else:
label = self.input_dict[key][0]
tk.Label(self.container, text=label).grid(row=ind, column=0, columnspan=2, sticky='ns')
self.ent1[-1] = tk.Entry(self.container, width=10, background='white',
textvariable=self.entry_col1, state='normal')
self.ent1[-1].grid(row=ind, column=2, columnspan=2, sticky='ns')
def naccheck(self):
if self.nac[-1].get() == 0:
self.ent2[-1].configure(state='disabled')
else:
self.ent2[-1].configure(state='normal')
if __name__ == '__main__':
main_root = tk.Tk()
input_frame = tk.Frame(main_root, padx=10, pady=5)
input_frame.grid(row=0, sticky='ns')
input_steps = tk.Frame(main_root, padx=10, pady=5)
input_steps.grid(row=1, sticky='ns')
button_first_frame = tk.Frame(main_root, padx=10, pady=5)
button_first_frame.grid(row=2, sticky='ns')
dict_inp = create_input_dictionary()
gui = gui(main_root)
gui.make_entry(input_frame, dict_inp)
button = tk.Button(button_first_frame, text="click me", command=lambda: print(dict_inp))
button.grid(row=0, columnspan=3)
main_root.mainloop()
But I cannot figure out why the entries and checkboxes are dependent
CodePudding user response:
Here is one approach:
import tkinter as tk
out = {
'Header 1': ['DATA', 'Min', 'Max'],
'Do': ['Lab1', 'mm', '25', '35'],
'Di': ['Lab1', 'mm', '25', '35'],
'nos': ['Lab9', '10']
}
class DataRow(tk.Frame):
def __init__(self, parent, label, lst, **kwargs):
super().__init__(parent, **kwargs)
self.lst = lst
self.columnconfigure(tuple(range(4)), weight=1, minsize=100)
tk.Label(self, text=label).grid(row=0, column=0, sticky='w')
self.entry1 = tk.Entry(self)
self.entry1.grid(row=0, column=1)
self.entry1.insert('end', lst[-2])
self.entry2 = tk.Entry(self)
self.entry2.grid(row=0, column=3)
self.entry2.insert('end', lst[-1])
self.var = tk.IntVar(master=self, value=1)
self.check = tk.Checkbutton(
self, text='Enabled', command=self.enabled, onvalue=1, offvalue=0,
variable=self.var
)
self.check.grid(row=0, column=2)
def enabled(self):
if self.var.get():
self.entry2.config(state='normal')
else:
self.entry2.config(state='disabled')
def update_data(self):
self.lst[-2:] = self.entry1.get(), self.entry2.get()
def update_dict():
for row in data_rows:
row.update_data()
root = tk.Tk()
data_rows = []
for key, value in out.items():
dr = DataRow(root, key, value)
dr.pack(expand=True, fill='both')
data_rows.append(dr)
tk.Button(
root, text='Update', command=update_dict
).pack(side='bottom', expand=True, fill='both')
root.mainloop()
Create a class that will represent one of the rows, in the class simply define the label, the two entries and the checkbutton, create methods for updating the lists and a method for enabling the button. Then create these rows in a loop iterating over the dictionary and add the DataRow
s to a list. Then assign a function to the button that will go over that list and call the updating functions on each data row, that will update the lists.