pythontkintergridcustomtkinterdynamic-tables

Re-arranging rows in a table Customtkinter


I am currently trying to figure out how to do the following:

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. Up to this point the app works very well. However I am having a hard time figuring out how to create two more functions that run with the buttons created in the for-loop that move an specific row up or down.

The 'UP' button for example, in row 5, needs to move the row 5 of entry widgets up to row 4, while bringing the row previusly positioned in row 4 to row 5. See below:

How it looks BEFORE pressing "up" button in row 5 (click here)

How it looks AFTER pressing "up" button in row 5 (click here)

I have figured out how to swap the entry widgets, however what happens after when I tried to move row 4 to row 3 and row 3 to 4 after succesfully doing row 5 and 4, this happens, see below:

what happens AFTER pressing "up" button in row 4 (click here)

Also I would like stop row #1 to move up since it is the first row, there is nowhere to go, however I am having an issue making a condition to avoid that. See below:

What happens when pressing "up" button in row 1

I also would appreciatte very much that if someone has a better solution than the button up and down for dyanmically re-aaranging the rows in these table, please advise. I am opened to anything. For exmaple I have been reading about the drag and drop method, however it seems a bit more complicated and I do notknow if it's possible to do/use on this layout

import customtkinter
# from functools import partial

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)
    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)
    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():
    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

def deleterow():
    delete()


def up(row): #FUNCTION I AM TRYING TO FIGURE OUT

    for column in range(columns):

        index=(row,column)
        _entry[row,column].grid_configure(row=row, column=column+1)
        _entry[row-1,column].grid_configure(row=row+1, column=column+1)



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) #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

  • You need to update the dictionary _entry as well:

    def up(row): #FUNCTION I AM TRYING TO FIGURE OUT
        # don't move first row up
        if row > 0:
            for column in range(columns):
                #index=(row,column)  # not used
                _entry[row,column].grid_configure(row=row, column=column+1)
                _entry[row-1,column].grid_configure(row=row+1, column=column+1)
                # swap _entry dictionary
                _entry[row,column], _entry[row-1,column] = _entry[row-1,column], _entry[row,column]