1

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.

  • I think its easier to let your user choose which particular string they wants to modify? Like using a `Combobox`. – Henry Yik Oct 06 '20 at 04:20
  • 1
    Use a `Listbox` to hold the list of strings and an `Entry` to edit the selected string in `Listbox`. – acw1668 Oct 06 '20 at 04:35

2 Answers2

1

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()
j_4321
  • 15,431
  • 3
  • 34
  • 61
0

Another solution would be to use a Text() object, which I had forgotten about because of my lack of use of them.

def edit_current_build(self,build_window,build):
    perkList=tk.Text(build_window,width=59)
    perkList.grid()

    perkScrollbar=tk.Scrollbar(build_window,orient='vertical',command=perkList.yview)
    perkScrollbar.grid(row=0,column=1,sticky='ns')
    perkList.configure(yscrollcommand=perkScrollbar.set)

    for line in build:
        perkList.insert(END,line)

        tk.Button(build_window,text='Save',command=lambda:self.save(build_window,build,perkList)).grid(sticky=W)

def save(self,build_window,build,perkList):
    currentBuild=[]
    for line in perkList.get('1.0','end-1c').split('\n'): # seperates lines but '\n' is added later as I still want the newlines
        line+='\n'
        currentBuild.append(line)