Search code examples
pythondictionarytkintercustomtkinter

Why Dictionary of widgets does not update when deleting CTkEntry Widgets?


NOTE: This is a code I used in a previous question for different reasons.

I have created a window that contains a table(frame) with Entry widgets, Label widgets, checkbox widgets and button widgets using for-loops. The window also has two buttons (outside the table) that allow the user to either insert new rows or delete them. This works fine.

However, the function that inserts a new row updated the widget dictionary, while the other function(delete row function) does not update the widget dictionary. I added print(_entry) at the end of both functions for you to see the difference

I do no know why it does not update it. I have tried by adding a return inside the delete() function, but it does not seem to be working.

I'd very much appreciate your help on this

See code below:



import customtkinter


customtkinter.FontManager.load_font("Industry-Book.otf")
customtkinter.FontManager.load_font("Industry-Medium.otf")
customtkinter.FontManager.load_font("Industry-Demi.otf")


def append():
    global row, rows,currenth
    row = rows
    for column in range(columns):
        index = (row, column)
        e = customtkinter.CTkEntry(framedash, validate="key",justify='c',fg_color='#27333B',border_color='#D1D3D4')#, validatecommand=self.vcmd)
        e.grid(row=row+1, column=column+1, stick="nsew")
        _entry[index] = e
    l1 = customtkinter.CTkLabel(framedash, text=row + 1, font=("Industry-Medium", 14),bg_color='#8F8F8F',width=40)  # setting a lable/text
    l1.grid(row=row+1, column=0, columnspan=1, padx=1, pady=1,stick="nsew")
    cb = customtkinter.CTkCheckBox(framedash, text='', width=0)
    cb.grid(row=row + 1, column=5, columnspan=1, padx=1, pady=1, stick="nsew")
    downbutton = customtkinter.CTkButton(framedash, text='DW', width=20, height=20,command=lambda  row=row:down(row))
    downbutton.grid(row=row + 1, column=6, columnspan=1, padx=1, pady=1, stick="nsew")
    upbutton = customtkinter.CTkButton(framedash, text='UP', width=20, height=20,command=lambda row=row:up(row))
    upbutton.grid(row=row + 1, column=7, columnspan=1, padx=1, pady=1, stick="nsew")

    _entry1[index] = l1
    _entry2[index] = cb
    _entry3[index] = downbutton
    _entry4[index] = upbutton

    currenth = currenth + 30
    dashboard.geometry(f'450x{currenth}')
    rows += 1
    print(_entry)



def addrow():
    append()


def delete(): #THIS IS THE FUNCTION THAT DOES NOT UPDATE THE _entry dictionary
    global row, rows, currenth
    if rows==1:
        return False
    else:
        row = rows-1
        for column in range(columns):
            index = (row, column)
            _entry[index].grid_remove()
        _entry1[index].grid_remove()
        _entry2[index].grid_remove()
        _entry3[index].grid_remove()
        _entry4[index].grid_remove()
        currenth = currenth - 30
        dashboard.geometry(f'450x{currenth}')
        rows -= 1
        print(_entry)

def deleterow():
    delete()


currenth=380
dashboard = customtkinter.CTk(fg_color='#27333b')
dashboard.geometry(f"450x{currenth}") #size of window
dashboard.title('Itipack Systems Cals') #tittle of the window
dashboard.attributes('-topmost', True)  # note - before topmost
dashboard.resizable(False, False)
dashboard.after(201, lambda: dashboard.iconbitmap('Itipack_icon_cmyk_rev_l.ico'))

_entry = {}
_entry1 = {}
_entry2 = {}
_entry3 = {}
_entry4 = {}
rows=9
columns =2
table = [columns,rows]

framedash = customtkinter.CTkFrame(dashboard,width=600,height=600,fg_color='#27333b')
framedash.grid(row=2,column=0,padx=10,pady=10,columnspan=columns+4,rowspan=rows+1,sticky='')


c1 = customtkinter.CTkLabel(framedash,text='FUNCTION',font=("Industry-Medium",14),bg_color='grey',width=60) #setting a lable/text
c1.grid(row=0, column=1, columnspan=1, padx=1, pady=1,sticky='nesw') #location?

c2 = customtkinter.CTkLabel(framedash,text='DURATION',font=("Industry-Medium",14),bg_color='grey',width=40) #setting a lable/text
c2.grid(row=0, column=2, columnspan=1, padx=1, pady=1,sticky='nesw') #location?



for row in range(rows):
    l1 = customtkinter.CTkLabel(framedash, text=row+1, font=("Industry-Medium",14),bg_color='#8F8F8F',width=40)  # setting a lable/text
    l1.grid(row=row+1, column=0, columnspan=1, padx=1, pady=1, stick="nsew")
    cb= customtkinter.CTkCheckBox(framedash,text='',width=0)
    cb.grid(row=row+1, column=5, columnspan=1, padx=1, pady=1, stick="nsew")
    downbutton = customtkinter.CTkButton(framedash,text='DW',width=20,height=20,command=lambda  row=row:down(row)) #lamda expression to give the command to every button
    downbutton.grid(row=row + 1, column=6, columnspan=1, padx=1, pady=1, stick="nsew")
    upbutton = customtkinter.CTkButton(framedash,text='UP',width=20,height=20,command=lambda row=row:up(row))
    upbutton.grid(row=row + 1, column=7, columnspan=1, padx=1, pady=1, stick="nsew")

    for column in range(columns):
        index = (row, column)
        e = customtkinter.CTkEntry(framedash, validate="key",justify='c',fg_color='#27333B',border_color='#D1D3D4')#, #validatecommand=self.vcmd)
        e.grid_configure(row=row+1, column=column+1,padx=1, pady=1, stick="nsew")
        _entry[index] = e
    _entry1[index] = l1
    _entry2[index] = cb
    _entry3[index]= downbutton
    _entry4[index]=upbutton

# adjust column weights so they all expand equally
for column in range(columns):
    framedash.grid_columnconfigure(column, weight=0)
# designate a final, empty row to fill up any extra space
framedash.grid_rowconfigure(rows, weight=0)

button1 = customtkinter.CTkButton(dashboard, width=50, height=50, text='A', font=("Industry-Medium", 16),
                                  corner_radius=1, fg_color='#00AAE9',
                                  command=addrow)  # , command=calculate)
button1.grid(row=0, column=0, padx=5, pady=5, sticky='e')


button1 = customtkinter.CTkButton(dashboard, width=50, height=50, text='D', font=("Industry-Medium", 16),
                                  corner_radius=1, fg_color='#00AAE9',
                                  command=deleterow)  # , command=calculate)
button1.grid(row=0, column=1, padx=5, pady=5, sticky='w')

button1 = customtkinter.CTkButton(dashboard, width=50, height=50, text='S', font=("Industry-Medium", 16),
                                  corner_radius=1, fg_color='#00AAE9')  # , command=calculate)
button1.grid(row=0, column=2, padx=5, pady=5)

label12=customtkinter.CTkEntry(dashboard,width=50,height=30,justify='c')
label12.grid(row=0, column=4, padx=5, pady=5,sticky='w')

label12=customtkinter.CTkLabel(dashboard,text='# STRAPS',font=("Industry-Medium", 16))
label12.grid(row=0, column=3, padx=5, pady=5,sticky='e')

dashboard.grid_columnconfigure(0, weight=1)
dashboard.grid_columnconfigure(1, weight=1)
dashboard.grid_columnconfigure(2, weight=1)
dashboard.grid_columnconfigure(3, weight=1)
dashboard.grid_columnconfigure(4, weight=1)
dashboard.grid_columnconfigure(5, weight=1)
dashboard.mainloop()

Solution

  • Calling .grid_remove() will only remove the widget from the MMI and the widget still exists in the dictionary.

    You can use .pop(index) to remove and return the widget from the dictionary, and then call .destroy() to destroy the widget.

    def delete():
        global row, rows, currenth
        if rows==1:
            return False
        else:
            row = rows-1
            for column in range(columns):
                index = (row, column)
                _entry.pop(index).destroy()
            _entry1.pop(index).destroy()
            _entry2.pop(index).destroy()
            _entry3.pop(index).destroy()
            _entry4.pop(index).destroy()
            currenth = currenth - 30
            dashboard.geometry(f'450x{currenth}')
            rows -= 1
            print(_entry)