Search code examples
pythontkintertkinter-entry

What would be the best way for a user to be able to view a list of strings and edit those strings in a tkinter window?


The title probably makes my goal sound a little confusing since I wasn't sure of the best way to word it but I'd like to add the ability to edit a list of strings, allow a user to edit them, and then save them to the program that I'm currently working on. An easy way would be to create a label with an entry that corresponds to it and set the value of a variable to entry.get(). Such as:

row=0
for line in build: # build is a list of strings
    Label(build_window,text=line).grid(row=row,column=0,sticky=W) 
    # build_window is a Toplevel of 'main_screen'
    Entry(build_window).grid(row=row,column=1,sticky=W) 
    # I know I'd need to save the entry as a variable or some other way in order to access
    # the value but I left it like this for demonstration
    row+=1

This would create a label and an entry on the same row, then the value of entry.get() would be saved. But the problem is that build contains 50+ lines of strings and this setup would need a very large amount of space in order to use. Would you be able to use Listbox() and Scrollbar() in order to achieve this effect? (Asking as that's how I've listed them previously in my program) I've tried indexing a Listbox() object like you would a normal list (ListboxObject[1]) but it just returns an error saying that it takes a string, not an int.


Solution

  • As suggested by acw1668, you can use a combination of a Listbox and an Entry. Each time the selection of the listbox changes (<<ListboxSelect>> event), the content of the entry is set to the currently selected string. Then the user can edit the string in the entry and click on the edit button to validate the change.

    import tkinter as tk
    
    def on_listbox_select(event):
        index = listbox.curselection()  # get index of selected line in listbox
        entry.delete(0, 'end')          # clear the entry
        if not index:
            return
        entry.insert(0, listbox.get(index))  # put the selected string in the entry
    
    def edit():
        index = listbox.curselection()  # get index of selected line in listbox
        if not index:  
            return  # no selected line, do nothing
        # replace lisbox line with new string
        listbox.delete(index)  
        listbox.insert(index, entry.get())
        listbox.see(index)
        entry.delete(0, 'end')  # clear the entry
    
    root = tk.Tk()
    root.rowconfigure(0, weight=1)
    build = ['string %i' % i for i in range(50)]
    listbox = tk.Listbox(root, exportselection=False)
    listbox.grid(row=0, column=0, sticky='ewsn')
    # scrollbar
    sb = tk.Scrollbar(root, orient='vertical', command=listbox.yview)
    sb.grid(row=0, column=1, sticky='ns')
    listbox.configure(yscrollcommand=sb.set)
    # put content in listbox
    for line in build:
        listbox.insert('end', line)
    # entry to edit the strings
    entry = tk.Entry(root)
    entry.grid(row=1, column=0, sticky='ew')
    # validate button
    tk.Button(root, text='Edit', command=edit).grid(row=2)
    
    listbox.bind('<<ListboxSelect>>', on_listbox_select)
    root.mainloop()