0
votes

This is the Tkinter window when calling addFilterList(list) I called this function like so:

tkWindow = TkWindow()
tkWindow.addFilterList(['A','B','C','D','E','F','G','H','I','J','K','L'])
tkwindow.runwindow()

I have this TKinker class. I am stuck on ways to make this more dynamic. First the scroll bar, buttons, and listbox are hard coded to be in specific places in the window. Is there a way to get this format no matter where on the Tkinter window it appears. For example, If I have a bunch of buttons on top, I would like the this feature to appear in this format without having to go back to the code and change its row or column location.

Second: The way I set it up, there can only be one addFilterList per TkWindow because of the return value. Can someone point me in the right directions in how to alter the code so that I can return the values of multiple Listbox in one Tkinter window.

class TkWindow(object):

def __init__(self):
    self.top = tk.Tk()

def addFilterList(self, list_box):
    self.list_box = list_box

    self.value = []

    self.text_field = tk.StringVar()

    self.entry = tk.Entry(self.top, textvariable=self.text_field, width=60)
    self.listbox = tk.Listbox(self.top, width=40, selectmode=tk.MULTIPLE)
    self.entry.grid()
    self.listbox.grid(row=7)

    self.text_field.trace("w", lambda name, index, mode: self.update_list())


    self.button_show = tk.Button(self.top, text="Select",
                                 command=self.selected_item)
    self.button_clear = tk.Button(self.top, text="Clear",
                                  command=self.clear)
    self.scrollbar = tk.Scrollbar(self.top)
    self.show_list = tk.Listbox(self.top, width=60, height=4)
    self.scrollbar.grid(row=7, sticky=tk.N + tk.S + tk.E, padx=(10, 50))
    self.button_show.grid(row=8, padx=(10, 300))
    self.button_clear.grid(row=8, sticky=tk.E, padx=(10, 100))
    self.show_list.grid()

    # Add scrollbar
    self.listbox.config(yscrollcommand=self.scrollbar.set)
    self.scrollbar.config(command=self.listbox.yview)
    self.update_list()

def update_list(self):
    # Used in addFilterList()
    search_term = self.text_field.get()
    self.listbox.delete(0, tk.END)
    for item in self.list_box:
        if search_term.lower() in item.lower():
            self.listbox.insert(tk.END, item)

def selected_list(self):
    # Used in addFilterList()
    self.show_list.delete(0, tk.END)
    for item in self.value:
        self.show_list.insert(tk.END, item)
    self.selected = self.listbox.selection_clear(0, tk.END)

def selected_item(self):
    # Used in addFilterList()
    self.selected = self.listbox.curselection()
    for i in self.selected:
        self.value.append(self.listbox.get(i))
    self.selected_list()

def clear(self):
    # Used in addFilterList()
    self.value = []
    self.show_list.delete(0, tk.END)

def return_value(self):
    return self.value

def runWindow(self):
    self.top.mainloop()
1

1 Answers

1
votes

I'm not sure I understand your question but I will try to offer some advice. I think you are trying to do too many things in the function addFilterList. Your code is hard to read and modify as a result. You have three distinct things to be done:

  1. Initializing the widgets
  2. Laying out the widgets
  3. Populating the widgets with values

I usually do #1 in the constructor. So your constructor would be, in outline:

def __init__(self):
   self.top = tk.Tk()
   self.entry = tk.Entry(...)
   self.listbox = tk.ListBox(...)

Then I do the layout in a separate function, call it doLayout():

def doLayout(self):
    self.entry.grid(...)
    self.listbox.grid(...)

Now your function addFilterList can be concerned ONLY with adding a list of items to your listbox. You can change the layout without changing this function. You can add additional widgets to the window without changing this function.

If you want to have more than one FilterList, you might consider making a subclass of tk.Listbox. The functions here would set the list contents, clear the list contents, handle list selection events and so forth. Then if you decide you want two lists instead of just one, you can instantiate another instance of this class and add that to your window.