'Python Tkinter: Insert objects into listbox, and then get them out (not as string)

I have a listbox that displays some objects:

# extra is some array of 'extra' objects I get from a database
self.extrasList = Listbox(self, selectmode='multiple')
self.extrasList.pack(fill=X, expand=True)
for extra in extras:
    self.extrasList.insert(END, extra)

The extra objects have their __str__ overridden, so they display just fine.

However, when I then later do:

selection = self.extrasList.curselection()
extra = self.extrasList.get(selection[0]) #this is now a string rather than the proper 'extra' object

Is there a way to get the object back out of the listbox? Rather than a string?

The only thing I could find was to manually keep the listbox and an other list in sync. But this can be quite errorprone.



Solution 1:[1]

No, there is no way to get the data out of a listbox as anything other than a string.

Solution 2:[2]

You could try something like this: Put the objects into a dictionary (the strings as keys and the objects as values) and insert the keys into the listbox, then retrieve the selected keys with listbox.selection_get().split() and use them to get the desired objects out of the dict.

import tkinter as tk

root = tk.Tk()

def print_selection(event):
    for key in listbox.selection_get().split():
        print(extras[key])

extras = {
    'object1': 1,
    'object2': 2,
    }

listbox = tk.Listbox(root, selectmode='multiple')
for key in extras:
    listbox.insert('end', key)
listbox.grid(row=0, column=0)
listbox.bind('<Key-Return>', print_selection)
tk.mainloop()

Solution 3:[3]

class Test:
    def __init__(self,name):
        self.name=name
    def __str__(self):
        return self.name

test=Test('MY OBJECT')

Assume that you inserted to your listbox test object and it will shown in your listbox as a string listbox=['MY_OBJECT'] name.

You can get your object easily like that in your listbox -> First of all, save your test object in an empty list:

my_list=[test]

After that you can understand easily which object selected or not with a for loop:

for get_string in listbox:
    for obj in my_list:
        if get_string == obj.__str__():
            print(f' You Selected {obj}')

Solution 4:[4]

The answer is to store your objects in an underlying data structure (just an array), and have the listbox be a simple view of those objects. When you click on the item in the listbox, you can use the index to get the actual object from the underlying array.

e.g., hacky pseudocode:

class MyListThing:
  def __init__(self, a): self.a = a
  def display(): return "My val is {a}"

... later, in your GUI:

class MyGui:

  # The "model"
  self.listObjects = []
  self.listObjects.append(MyListThing(1))

  # The "view"
  self.listbox = Listbox(...)

  # load the view (use this when the list contents change)
  def reload_list(self):
    self.listbox.delete(0, END)
    for b in self.listObjects:
      self.listbox.insert(END, b.display())

  # Get the current _actual object_
  def on_select(self, event):
    s = self.listbox.curselection()
    if len(s) == 0:
      return
    index = int(s[0])
    b = self.listObjects[index]
    print ('object selected: {(index, b.display())}')
    # ... do whatever with the actual object now.

Cheers! jz

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bryan Oakley
Solution 2 skrx
Solution 3 Abdulmecid Pamuk
Solution 4 J.Z.