Python自制IDE实现文件树遇FileNotFoundError,求修复方案
问题描述
用Python结合Tkinter开发IDE趣味项目,实现VS Code风格文件树功能时遇到问题:点击文件树中的文件会报错FileNotFoundError: [Errno 2] No such file or directory: './file.py',推测是程序在主文件所在目录查找目标文件,而非文件实际所在目录。
原代码如下:
######################################## #TREE ######################################## file_tree = Frame(root) file_tree.pack(side='left', fill=Y, expand=NO) def open_dir(): for i in tree.get_children(): tree.delete(i) path = askdirectory() abspath = os.path.abspath(path) root_node = tree.insert('', 'end', text=abspath, open=True) process_directory(root_node,abspath) def process_directory( parent, path): for p in os.listdir(path): abspath = os.path.join(path, p) isdir = os.path.isdir(abspath) oid = tree.insert(parent, 'end', text=p, open=False) if isdir: process_directory(oid, abspath) def Open_file_from_list_box(value): global file item_id = tree.selection() file = tree.item(item_id, 'text') # get the filename from 'text' option filepath = os.path.join(value,file) editArea.delete(1.0,END) with open(filepath,"r") as f: editArea.insert(1.0,f.read()) tree = ttk.Treeview(file_tree) tree.pack(expand=YES,fill=BOTH) path = '.' tree.heading('#0', text=path, anchor='w') abspath = os.path.abspath(path) root_node = tree.insert('', 'end', text=abspath, open=True) process_directory(root_node, abspath) tree.bind("<<TreeviewSelect>>",lambda event=None:Open_file_from_list_box(path))
问题根源
- 绑定事件时传入的
path始终是初始值.,并非选中文件所在的实际目录 tree.item(item_id, 'text')仅获取文件名/目录名,未保留完整路径信息,拼接后的路径指向主文件目录而非文件真实位置
修复方案
方法一:存储完整路径到Treeview节点(推荐)
修改代码,在插入Treeview节点时将文件/目录的完整路径存入values属性,打开文件时直接读取该值:
- 修改
process_directory函数:
def process_directory(parent, path): for p in os.listdir(path): abspath = os.path.join(path, p) isdir = os.path.isdir(abspath) # 插入节点时存入完整路径到values oid = tree.insert(parent, 'end', text=p, open=False, values=(abspath,)) if isdir: process_directory(oid, abspath)
- 修改
Open_file_from_list_box函数:
def Open_file_from_list_box(event=None): item_id = tree.selection() # 从values中取出完整路径 filepath = tree.item(item_id, 'values')[0] # 仅处理文件,避免点击目录报错 if os.path.isfile(filepath): editArea.delete(1.0, END) with open(filepath, "r") as f: editArea.insert(1.0, f.read())
- 更新
open_dir和初始节点插入代码,同样存入完整路径:
# open_dir函数内的root_node插入 root_node = tree.insert('', 'end', text=abspath, open=True, values=(abspath,)) # 初始root_node插入 root_node = tree.insert('', 'end', text=abspath, open=True, values=(abspath,))
- 修改事件绑定:
tree.bind("<<TreeviewSelect>>", Open_file_from_list_box)
方法二:递归拼接父节点路径
若不想存储额外属性,可通过递归获取父节点的文本拼接出完整路径:
- 添加路径拼接函数:
def get_full_path(item_id): path = tree.item(item_id, 'text') parent_id = tree.parent(item_id) while parent_id: parent_path = tree.item(parent_id, 'text') path = os.path.join(parent_path, path) parent_id = tree.parent(parent_id) return os.path.abspath(path)
- 修改
Open_file_from_list_box函数:
def Open_file_from_list_box(event=None): item_id = tree.selection() filepath = get_full_path(item_id) if os.path.isfile(filepath): editArea.delete(1.0, END) with open(filepath, "r") as f: editArea.insert(1.0, f.read())
- 修改事件绑定:
tree.bind("<<TreeviewSelect>>", Open_file_from_list_box)
注:方法二需确保所有节点的
text都是正确的路径片段,若存在重命名显示等场景,可能出现路径错误,推荐使用方法一。
内容的提问来源于stack exchange,提问作者some_dude
相关产品推荐
相关产品推荐

