Tkinter Listbox: manipulate display of rows (or display one column but `curselection` another from same dataframe)

Tags: , ,



I am currently displaying in a Listbox a column of a pandas DataFrame which contains the full path of some files I need to work on. Right now it all works fine because I am displaying the full path in the Listbox, so that in my on_select I get the full path as current_selection_text and I can work on this item at my will.

def on_select(event,**kwargs):
    # display element selected on list
    current_selection_text=event.widget.get(event.widget.curselection())

Full path is quite long usually so I want to not display it and display just the filename, still being able to select the full path without displaying the full path because it’s just clutter.

My question is if there is a way to display the filename in the Listbox and at the same time selecting the corresponding full path. The only way ahead that I see to achieve is:

  • Listbox could provide functionality to display a function of the list that I have filled it with. To be concrete I fill it by my_listbox.inset(end, x) but then in the GUI I want to see f(x). As there seems to be no control on how the items are displayed in Listbox I am unable to proceed (to be precise: the official doc has no mention of Listbox, and the best reference I found says nothing about manipulating the display of the Listbox.

In alternative I thought of trying to display the DataFrame itself (or a subset of the columns) via pandastable instead of a Listbox. At that point I might select the row(s) I need and apply the functions I need. This seems quite a bigger gun to solve this problem, plus I never used pandastable so I might not see roadblocks ahead. Suggestions are very welcome (if necessary I am willing to try other GUI makers such as pyQT).

Answer

There’s no direct support, but it’s trivial to keep a list of full paths synchronized with the list of filenames.

import tkinter as tk
from pathlib import Path

paths = [
    "/tmp/foo.py",
    "/tmp/bar.py",
    "/user/somebody/baz.py",
]

def get_selected_path(event):
    listbox = event.widget
    selection = listbox.curselection()
    if selection:
        index = selection[0]
        full_path = paths[index]
        label.configure(text=full_path)

root = tk.Tk()
listbox = tk.Listbox(root)
label = tk.Label(root, anchor="w")

label.pack(side="bottom", fill="x")
listbox.pack(fill="both", expand=True)

listbox.bind("<<ListboxSelect>>", get_selected_path)
for path in paths:
    name = Path(path).name
    listbox.insert("end", name)

root.mainloop()

screenshot



Source: stackoverflow