i have difficulties adding rows below each button where the "add row" button is located. My program somehow places the new rows at different locations other than directly below it.
could you please show me where my logic error is?
import tkinter as tkfrom tkinter import ttkfrom PIL import Image, ImageTkdropdown_values_dict = {}def get_identifier(tab_index, section_name, row_name): return f"tab_{tab_index}_{section_name}_{row_name}"def store_input(entry, dropdown_menu, identifier): input_text = entry.get() if input_text: dropdown_values = set(dropdown_menu['values']) # Convert to set to remove duplicates dropdown_values.add(input_text) dropdown_menu['values'] = sorted(dropdown_values, key=lambda x: (isinstance(x, str), x)) # Sort values alphabetically dropdown_menu.current(len(dropdown_menu['values']) - 1) entry.delete(0, tk.END) save_dropdown_values(identifier, list(dropdown_values)) # Save unique values without duplicates update_dropdown_values_dict(identifier, list(dropdown_values)) # Ensure that the dictionary exists for the identifier existing_dict = dropdown_values_dict.get(identifier, {}) # Update existing dictionary with new input existing_dict[input_text] = True dropdown_values_dict[identifier] = existing_dictdef remove_selected(dropdown_menu, identifier): selected_index = dropdown_menu.current() dropdown_values = list(dropdown_menu['values']) if selected_index != -1: del dropdown_values[selected_index] dropdown_menu['values'] = dropdown_values if dropdown_values: # Check if there are still items in the menu dropdown_menu.current(0) # Set selection to the first item else: dropdown_menu.set("") # Reset selection if no items left save_dropdown_values(identifier, dropdown_values) update_dropdown_values_dict(identifier, dropdown_values) dropdown_values_dict[identifier] = dropdown_values # Update the dictionary for the rowdef add_new_row(tab, section_index, row_num, row_name, identifier, add_button): # Ensure correct section handling section_offset = section_index * 8 # Find the index of the clicked row in the grid clicked_row_index = row_num # Update the row indices of existing rows below the clicked row for slave in tab.grid_slaves(): info = slave.grid_info() slave_row = int(info.get('row', 0)) if slave_row > clicked_row_index: slave.grid(row=slave_row + 1, column=info['column']) new_row_num = clicked_row_index + 1 # Create new widgets for the new row text_label = tk.Label(tab, text=f"{row_name}:") text_label.grid(row=new_row_num, column=0, padx=5, pady=5, sticky="w") entry = tk.Entry(tab) entry.grid(row=new_row_num, column=1, padx=5, pady=5, sticky="ew") dropdown_var = tk.StringVar() dropdown_menu = ttk.Combobox(tab, textvariable=dropdown_var, state="readonly") dropdown_menu.grid(row=new_row_num, column=2, padx=5, pady=5, sticky="w") dropdown_values = load_dropdown_values(identifier) dropdown_menu['values'] = dropdown_values update_dropdown_values_dict(identifier, dropdown_values) store_button = tk.Button(tab, text="Store", command=lambda entry=entry, dropdown_menu=dropdown_menu, identifier=identifier: store_input(entry, dropdown_menu, identifier)) store_button.grid(row=new_row_num, column=3, padx=5, pady=5, sticky="w") remove_button = tk.Button(tab, text="Remove", command=lambda dropdown_menu=dropdown_menu, identifier=identifier: remove_selected(dropdown_menu, identifier)) remove_button.grid(row=new_row_num, column=4, padx=5, pady=5, sticky="w") # Ensure that the dictionary exists for the identifier dropdown_values_dict.setdefault(identifier, []) # Update the dictionary for the row dropdown_values_dict[identifier].append(dropdown_values)def save_dropdown_values(identifier, values): with open(f"dropdown_values_{identifier}.txt", "w") as f: for value in values: f.write(value +"\n")def load_dropdown_values(identifier): try: with open(f"dropdown_values_{identifier}.txt", "r") as f: values = [line.strip() for line in f.readlines()] return sorted(values, key=lambda x: (isinstance(x, str), x)) # Sort by type and value except FileNotFoundError: return []def update_dropdown_values_dict(identifier, values): global dropdown_values_dict dropdown_values_dict[identifier] = valuesdef tab_content(tab_index, tab): sections = ["AL1", "AL2"] # Counters to keep track of occurrences of row names AL1_all_counter = 0 AL1_first_and_any_other_counter = 0 AL1_first_and_no_other_counter = 0 AL1_all_first_and_any_other_counter = 0 AL2_all_counter = 0 AL2_first_and_any_other_counter = 0 AL2_first_and_no_other_counter = 0 AL2_all_first_and_any_other_counter = 0 for section_index, section_name in enumerate(sections): # Label for section name section_label = tk.Label(tab, text=section_name) section_label.grid(row=(section_index * 8), column=0, columnspan=5, padx=5, pady=10, sticky="w") for i, row_name in enumerate(["ANY", "ALL", "ALL", "First and any other", "First and any other", "First and no other", "All first and any other"]): identifier = get_identifier(tab_index, section_name, row_name) row_num = i + (section_index * 8) + 1 # Initialize add_button as None add_button = None # Logic to determine which rows get an "Add Row" button if section_name == "AL1": if row_name == "ALL": AL1_all_counter += 1 if AL1_all_counter == 2: add_button = tk.Button(tab, text="Add Row") elif row_name == "First and any other": AL1_first_and_any_other_counter += 1 if AL1_first_and_any_other_counter == 2: add_button = tk.Button(tab, text="Add Row") elif row_name == "First and no other": AL1_first_and_no_other_counter += 1 if AL1_first_and_no_other_counter == 1: add_button = tk.Button(tab, text="Add Row") elif row_name == "All first and any other": AL1_all_first_and_any_other_counter += 1 if AL1_all_first_and_any_other_counter == 1: add_button = tk.Button(tab, text="Add Row") elif section_name == "AL2": if row_name == "ALL": AL2_all_counter += 1 if AL2_all_counter == 2: add_button = tk.Button(tab, text="Add Row") elif row_name == "First and any other": AL2_first_and_any_other_counter += 1 if AL2_first_and_any_other_counter == 2: add_button = tk.Button(tab, text="Add Row") elif row_name == "First and no other": AL2_first_and_no_other_counter += 1 if AL2_first_and_no_other_counter == 1: add_button = tk.Button(tab, text="Add Row") elif row_name == "All first and any other": AL2_all_first_and_any_other_counter += 1 if AL2_all_first_and_any_other_counter == 1: add_button = tk.Button(tab, text="Add Row") if add_button: add_button.config(command=lambda row_num=row_num, row_name=row_name, add_button=add_button: add_new_row(tab, section_index, row_num, row_name, identifier, add_button)) add_button.grid(row=row_num, column=5, padx=5, pady=5, sticky="w") # Initial row text_label = tk.Label(tab, text=f"{row_name}:") text_label.grid(row=row_num, column=0, padx=5, pady=5, sticky="w") entry = tk.Entry(tab) entry.grid(row=row_num, column=1, padx=5, pady=5, sticky="w") dropdown_var = tk.StringVar() dropdown_menu = ttk.Combobox(tab, textvariable=dropdown_var, state="readonly") dropdown_menu.grid(row=row_num, column=2, padx=5, pady=5, sticky="w") dropdown_values = load_dropdown_values(identifier) dropdown_menu['values'] = dropdown_values update_dropdown_values_dict(identifier, dropdown_values) store_button = tk.Button(tab, text="Store", command=lambda entry=entry, dropdown_menu=dropdown_menu, identifier=identifier: store_input(entry, dropdown_menu, identifier)) store_button.grid(row=row_num, column=3, padx=5, pady=5, sticky="w") remove_button = tk.Button(tab, text="Remove", command=lambda dropdown_menu=dropdown_menu, identifier=identifier: remove_selected(dropdown_menu, identifier)) remove_button.grid(row=row_num, column=4, padx=5, pady=5, sticky="w") dropdown_values_dict[identifier] = dropdown_values # Update the dictionary for the rowroot = tk.Tk()root.title("Tabbed GUI")# Create a Notebook (tabs container)notebook = ttk.Notebook(root)# Create tabstabs = []for i in range(4): tab = ttk.Frame(notebook) tabs.append(tab) notebook.add(tab, text=f'Tab {i+1}')notebook.pack(expand=1, fill='both')# Content for each tabfor i, tab in enumerate(tabs): tab_content(i, tab) # Pass the tab index and the tab to tab_contentroot.mainloop()
i tried to adjust the functions tab cotent and add new row. i was expecting the new rows to be inserted directly below each row where the add row button was clicked. instead, it seems like it randomly places the new rows at different lcations.