You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在可排序的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()

修改说明

  1. 在Drag_and_Drop_Listbox的初始化方法中新增self.full_paths列表,专门存储每个文件名对应的完整路径。
  2. 在sort函数中,插入文件名到Listbox的同时,将完整路径同步添加到full_paths列表,保证两者索引一一对应。
  3. 完善shiftSelection方法,在移动Listbox中的文件名时,同步调整full_paths中的对应路径,确保排序后文件名和路径的对应关系不被破坏。
  4. 修改save函数,直接遍历full_paths列表获取完整路径,无需通过文件名转换,彻底避免路径错误。

内容的提问来源于stack exchange,提问作者Ohtis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 10:24:59