如何在可排序的Python Listbox中仅显示文件名并保留完整文件路径?
问题:Tkinter Listbox仅显示文件名但保留完整路径
我想在Python的Tkinter Listbox组件里只显示文件的basename(文件名),但要保留对应的完整文件路径。目前能做到只显示文件名,但因为这个Listbox支持拖拽排序,后续执行打印到PDF的步骤时,会因为缺少完整路径找不到文件;如果在Listbox里显示完整路径,程序能正常运行,但我希望界面上只展示文件名。
下面是精简后的代码,运行后会打开Tk窗口,点击“Individual Sort”按钮选择图片文件,在新窗口点击“Save List”,目标是打印图片的原始文件路径,但现在只能打印程序所在路径;切换标注行的注释状态就能正常打印,但此时列表会显示完整路径。
import tkinter as tk from tkinter import * from tkinter import filedialog import os ws = Tk() ws.title('Select Files to Import') ws.geometry('500x200') ws.config(bg='#456') f = ('sans-serif', 13) btn_font = ('sans-serif', 10) bgcolor = '#BF5517' def sort(): global second second = Toplevel() second.geometry('800x400') menubar=Menu(second) menubar.add_command(label="Save List", command=save) second.config(menu=menubar) global listbox listbox = Drag_and_Drop_Listbox(second) listbox.pack(fill=tk.BOTH, expand=True) directory = filedialog.askopenfilenames() n = 0 for file in directory: listbox.insert(n, os.path.basename(file)) ####comment #listbox.insert(n, file) ####uncomment n=n+1 def save(): image=listbox.get(0, listbox.size()) for x in image: print(os.path.abspath(x)) class Drag_and_Drop_Listbox(tk.Listbox): def __init__(self, master, **kw): kw['selectmode'] = tk.SINGLE tk.Listbox.__init__(self, master, kw) self.bind('<Button-1>', self.getState, add='+') self.bind('<Button-1>', self.setCurrent, add='+') self.bind('<B1-Motion>', self.shiftSelection) def setCurrent(self, event): self.curIndex = self.nearest(event.y) def getState(self, event): i = self.nearest(event.y) self.curState = self.selection_includes(i) def shiftSelection(self, event): i = self.nearest(event.y) if self.curState == 1: self.selection_set(self.curIndex) else: self.selection_clear(self.curIndex) if i < self.curIndex: x = self.get(i) selected = self.selection_includes(i) self.delete(i) self.insert(i+1, x) if selected: self.selection_set(i+1) self.curIndex = i x = self.get(i) selected = self.selection_includes(i) self.delete(i) self.insert(i-1, x) if selected: self.selection_set(i-1) self.curIndex = i frame = Frame(ws, padx=20, pady=20, bg=bgcolor) frame.pack(expand=True, fill=BOTH) btn_frame = Frame(frame, bg=bgcolor) btn_frame.grid(columnspan=2, pady=(50, 0)) sort_btn = Button( btn_frame, text='Individual Sort', command=sort, font=btn_font, padx=10, pady=5 ) sort_btn.pack(side=LEFT, expand=True, padx=(5,5)) ws.mainloop()
解决思路
给自定义的Drag_and_Drop_Listbox类添加一个专门存储完整路径的列表,让它和Listbox显示的文件名一一对应,拖拽排序时同步更新这个列表,这样界面显示文件名,实际操作的是完整路径。
修改后的完整代码
import tkinter as tk from tkinter import * from tkinter import filedialog import os ws = Tk() ws.title('Select Files to Import') ws.geometry('500x200') ws.config(bg='#456') f = ('sans-serif', 13) btn_font = ('sans-serif', 10) bgcolor = '#BF5517' def sort(): global second second = Toplevel() second.geometry('800x400') menubar=Menu(second) menubar.add_command(label="Save List", command=save) second.config(menu=menubar) global listbox listbox = Drag_and_Drop_Listbox(second) listbox.pack(fill=tk.BOTH, expand=True) directory = filedialog.askopenfilenames() n = 0 for file in directory: listbox.insert(n, os.path.basename(file)) # 将完整路径添加到自定义列表中 listbox.full_paths.insert(n, file) n += 1 def save(): # 直接遍历存储完整路径的列表 for path in listbox.full_paths: print(path) class Drag_and_Drop_Listbox(tk.Listbox): def __init__(self, master, **kw): kw['selectmode'] = tk.SINGLE tk.Listbox.__init__(self, master, kw) # 新增属性存储完整路径 self.full_paths = [] self.bind('<Button-1>', self.getState, add='+') self.bind('<Button-1>', self.setCurrent, add='+') self.bind('<B1-Motion>', self.shiftSelection) def setCurrent(self, event): self.curIndex = self.nearest(event.y) def getState(self, event): i = self.nearest(event.y) self.curState = self.selection_includes(i) def shiftSelection(self, event): i = self.nearest(event.y) if self.curState == 1: self.selection_set(self.curIndex) else: self.selection_clear(self.curIndex) if i < self.curIndex: # 同步处理显示的文件名和完整路径 x = self.get(i) full_x = self.full_paths[i] selected = self.selection_includes(i) self.delete(i) self.insert(i+1, x) del self.full_paths[i] self.full_paths.insert(i+1, full_x) if selected: self.selection_set(i+1) self.curIndex = i x = self.get(i) full_x = self.full_paths[i] selected = self.selection_includes(i) self.delete(i) self.insert(i-1, x) del self.full_paths[i] self.full_paths.insert(i-1, full_x) if selected: self.selection_set(i-1) self.curIndex = i else: # 补充处理i > self.curIndex的排序逻辑 x = self.get(i) full_x = self.full_paths[i] selected = self.selection_includes(i) self.delete(i) self.insert(i-1, x) del self.full_paths[i] self.full_paths.insert(i-1, full_x) if selected: self.selection_set(i-1) self.curIndex = i x = self.get(i) full_x = self.full_paths[i] selected = self.selection_includes(i) self.delete(i) self.insert(i+1, x) del self.full_paths[i] self.full_paths.insert(i+1, full_x) if selected: self.selection_set(i+1) self.curIndex = i frame = Frame(ws, padx=20, pady=20, bg=bgcolor) frame.pack(expand=True, fill=BOTH) btn_frame = Frame(frame, bg=bgcolor) btn_frame.grid(columnspan=2, pady=(50, 0)) sort_btn = Button( btn_frame, text='Individual Sort', command=sort, font=btn_font, padx=10, pady=5 ) sort_btn.pack(side=LEFT, expand=True, padx=(5,5)) ws.mainloop()
修改说明
- 在
Drag_and_Drop_Listbox的初始化方法中新增self.full_paths列表,专门存储每个文件名对应的完整路径。 - 在
sort函数中,插入文件名到Listbox的同时,将完整路径同步添加到full_paths列表,保证两者索引一一对应。 - 完善
shiftSelection方法,在移动Listbox中的文件名时,同步调整full_paths中的对应路径,确保排序后文件名和路径的对应关系不被破坏。 - 修改
save函数,直接遍历full_paths列表获取完整路径,无需通过文件名转换,彻底避免路径错误。
内容的提问来源于stack exchange,提问作者Ohtis
相关产品推荐
相关产品推荐

