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

如何用Tkinter的filedialog同时选择文件和文件夹?

问题

在Python Tkinter中,需要通过filedialog同时选择文件和文件夹,但尝试askdirectory(仅能选择文件夹)和askopenfilenames(仅能选择文件)后,发现无法同时获取两者的选中列表,且官方文档中无对应专用对话框。

测试代码:

import tkinter as tk
from tkinter import filedialog

root = tk.Tk()
root.withdraw()

# 仅能选择文件
files_only = filedialog.askopenfilenames(parent=root, title="Select files and folders", multiple=True)

# 仅能选择文件夹
folders_only = filedialog.askdirectory(parent=root, title='Select files and folders', multiple=True)
解决方案

Tkinter原生filedialog不支持同时选择文件和文件夹,以下是两种可行实现方式:

方式1:自定义勾选式对话框

创建带列表框的自定义弹窗,让用户浏览文件系统并勾选需要的文件/文件夹,最后收集选中项:

import tkinter as tk
from tkinter import ttk, filedialog
import os

def select_items():
    def confirm_selection():
        selected = []
        current_path = path_var.get()
        for idx in listbox.curselection():
            item = listbox.get(idx)
            # 去除标识,还原真实路径
            real_name = item.replace("[DIR] ", "").replace("[FILE] ", "")
            selected.append(os.path.join(current_path, real_name))
        top.destroy()
        print("Selected items:", selected)

    def update_item_list():
        listbox.delete(0, tk.END)
        current_dir = path_var.get()
        for item in os.listdir(current_dir):
            full_path = os.path.join(current_dir, item)
            if os.path.isdir(full_path):
                listbox.insert(tk.END, f"[DIR] {item}")
            else:
                listbox.insert(tk.END, f"[FILE] {item}")

    def browse_dir():
        selected_dir = filedialog.askdirectory(initialdir=path_var.get())
        if selected_dir:
            path_var.set(selected_dir)
            update_item_list()

    # 弹窗初始化
    top = tk.Toplevel()
    top.title("Select Files & Folders")
    top.geometry("600x400")

    # 路径选择栏
    path_frame = ttk.Frame(top)
    path_frame.pack(padx=10, pady=5, fill=tk.X)
    path_var = tk.StringVar(value=os.path.expanduser("~"))
    path_entry = ttk.Entry(path_frame, textvariable=path_var)
    path_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0,5))
    browse_btn = ttk.Button(path_frame, text="Browse", command=browse_dir)
    browse_btn.pack(side=tk.RIGHT)

    # 文件/文件夹列表
    list_frame = ttk.Frame(top)
    list_frame.pack(padx=10, pady=5, fill=tk.BOTH, expand=True)
    listbox = tk.Listbox(list_frame, selectmode=tk.MULTIPLE)
    listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
    scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=listbox.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    listbox.config(yscrollcommand=scrollbar.set)
    update_item_list()

    # 确认按钮
    confirm_btn = ttk.Button(top, text="Confirm", command=confirm_selection)
    confirm_btn.pack(padx=10, pady=10)

    top.mainloop()

# 调用示例
if __name__ == "__main__":
    root = tk.Tk()
    root.withdraw()
    select_items()

方式2:使用第三方拖拽库(tkinterdnd2)

借助tkinterdnd2实现拖拽选择文件和文件夹,操作更直观:

import tkinter as tk
from tkinterdnd2 import DND_FILES, TkinterDnD

def handle_drop(event):
    # 解析拖拽的路径列表
    raw_paths = event.data.strip("{}").split("} {")
    print("Selected items:", raw_paths)

root = TkinterDnD.Tk()
root.title("Drag Files/Folders Here")
root.geometry("400x200")

drop_label = tk.Label(root, text="Drag files and folders to this area", padx=20, pady=50, bg="#f0f0f0")
drop_label.pack(fill=tk.BOTH, expand=True)
drop_label.drop_target_register(DND_FILES)
drop_label.dnd_bind('<<Drop>>', handle_drop)

root.mainloop()

注:需先通过pip install tkinterdnd2安装该库

总结

Tkinter原生无同时选择文件和文件夹的对话框,自定义对话框无需额外依赖,兼容性强;第三方库方式操作更简便,适合对交互体验要求较高的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:27:45