I'm encountering an issue with my Python File Explorer application and seeking guidance from fellow developers in the Python community. I've developed a simple file explorer using Tkinter, but I'm facing a problem specifically with the "This PC" section.
When I click on a folder or a drive in the left sidebar, it does not open as expected. The other sections like Desktop, Documents, etc., work perfectly fine. However, the issue arises when I attempt to navigate through the drives or folders under "This PC".
I've included the full script below for your reference. Could you please review it and provide insights into what might be causing this issue? Additionally, any suggestions or corrections to improve the functionality of the file explorer would be highly appreciated.
Thank you for your time and assistance!
import os
import tkinter as tk
from tkinter import ttk, messagebox
import time
import shutil
class FileExplorer(tk.Tk):
def __init__(self):
super().__init__()
self.title("File Explorer")
self.geometry("800x600")
self.sidebar = Sidebar(self)
self.toolbar = Toolbar(self)
self.breadcrumb = Breadcrumb(self)
self.file_list = FileList(self)
self.sidebar.pack(side='left', fill='y')
self.toolbar.pack(side='top', fill='x')
self.breadcrumb.pack(fill='x')
self.file_list.pack(expand=True, fill='both')
self.current_path = os.path.expanduser("~")
self.update_file_list()
def update_file_list(self):
if self.current_path == "This PC":
# Handle special case for This PC
drives = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
self.file_list.delete(*self.file_list.get_children())
for drive in drives:
try:
if os.path.exists(drive + ":\\"):
total_size = self.file_list.get_drive_size(drive)
self.file_list.insert('', 'end', text=drive + ":", values=('', '', total_size, ''))
except Exception as e:
print(f"Error getting drive info for {drive}: {e}")
else:
self.file_list.update_file_list(self.current_path)
self.breadcrumb.update_breadcrumb(self.current_path)
def change_directory(self, directory):
special_dirs = {
"Quick Access": os.path.expanduser("~"),
"Desktop": os.path.join(os.path.expanduser("~"), "Desktop"),
"Downloads": os.path.join(os.path.expanduser("~"), "Downloads"),
"Documents": os.path.join(os.path.expanduser("~"), "Documents"),
"Pictures": os.path.join(os.path.expanduser("~"), "Pictures"),
"Music": os.path.join(os.path.expanduser("~"), "Music"),
"Videos": os.path.join(os.path.expanduser("~"), "Videos"),
"This PC": "This PC",
"Network": None
}
if directory in special_dirs:
if directory == "This PC":
self.current_path = "This PC"
else:
self.current_path = special_dirs[directory]
else:
self.current_path = directory
self.update_file_list()
class Sidebar(tk.Frame):
def __init__(self, master, *args, **kwargs):
super().__init__(master, *args, **kwargs)
self.options = ["Quick Access", "Desktop", "Downloads", "Documents", "Pictures", "Music", "Videos", "This PC", "Network"]
self.create_sidebar()
def create_sidebar(self):
for option in self.options:
btn = tk.Button(self, text=option, bg='lightgrey', relief='flat', command=lambda o=option: self.master.change_directory(o))
btn.pack(fill='x')
class Toolbar(tk.Frame):
def __init__(self, master, *args, **kwargs):
super().__init__(master, bg='lightgrey', *args, **kwargs)
self.buttons = ["File", "Home", "Share", "View"]
self.create_toolbar()
def create_toolbar(self):
for btn_text in self.buttons:
btn = tk.Button(self, text=btn_text, command=lambda b=btn_text: self.toolbar_action(b))
btn.pack(side='left')
def toolbar_action(self, action):
if action == "File":
self.master.file_list.open_file_popup()
class Breadcrumb(tk.Label):
def __init__(self, master, *args, **kwargs):
super().__init__(master, text="", bg='lightgrey', anchor='w', relief='sunken', borderwidth=1, *args, **kwargs)
def update_breadcrumb(self, current_path):
self.config(text=current_path)
class FileList(ttk.Treeview):
def __init__(self, master, *args, **kwargs):
super().__init__(master, columns=("Extension", "Date", "Size", "Comments"), *args, **kwargs)
self.heading("#0", text="Name", anchor='w')
self.heading("Extension", text="Extension", anchor='w')
self.heading("Date", text="Date Modified", anchor='w')
self.heading("Size", text="Size", anchor='w')
self.heading("Comments", text="Comments", anchor='w')
self.column("#0", width=200, stretch=False)
self.column("Extension", width=100, stretch=False)
self.column("Date", width=150, stretch=False)
self.column("Size", width=100, stretch=False)
self.column("Comments", width=200, stretch=False)
self.bind("<Double-1>", self.on_file_open)
self.bind("<Button-3>", self.show_column_menu)
self.show_columns = {"Extension": False, "Date": False, "Size": False, "Comments": False}
def show_column_menu(self, event):
menu = tk.Menu(self, tearoff=0)
for column in self.show_columns.keys():
menu.add_checkbutton(label=column, command=lambda col=column: self.toggle_column(col), onvalue=True, offvalue=False, variable=tk.BooleanVar(value=self.show_columns[column]))
menu.add_separator()
menu.add_command(label="Others...", command=self.show_others_popup)
menu.post(event.x_root, event.y_root)
def show_others_popup(self):
popup = tk.Toplevel(self.master)
popup.title("Select Columns")
popup.geometry("300x400")
available_columns = ["Name", "Extension", "Date", "Size", "Comments"]
listbox = tk.Listbox(popup, selectmode=tk.MULTIPLE)
for col in available_columns:
listbox.insert(tk.END, col)
listbox.pack(expand=True, fill='both')
def apply_selection():
selected = listbox.curselection()
for col in available_columns:
self.show_columns[col] = False
for i in selected:
self.show_columns[available_columns[i]] = True
self.update_column_visibility()
popup.destroy()
button = tk.Button(popup, text="Apply", command=apply_selection)
button.pack()
def toggle_column(self, column):
self.show_columns[column] = not self.show_columns[column]
self.update_column_visibility()
def update_column_visibility(self):
for column, visible in self.show_columns.items():
if visible:
self.heading(column, text=column, anchor='w')
self.column(column, width=100, stretch=False)
else:
self.heading(column, text="")
self.column(column, width=0, stretch=False)
def get_drive_size(self, drive):
try:
total, used, free = shutil.disk_usage(drive + ":\\")
total_size = self.format_file_size(total)
return total_size
except:
return ""
def get_folder_size(self, folder):
total_size = 0
try:
for entry in os.scandir(folder):
if entry.is_file():
total_size += entry.stat().st_size
elif entry.is_dir():
total_size += self.get_folder_size(entry.path)
return self.format_file_size(total_size)
except:
return ""
def format_file_size(self, size):
if size < 1024:
return f"{size} B"
elif size < 1024 ** 2:
return f"{size / 1024:.1f} KB"
elif size < 1024 ** 3:
return f"{size / (1024 ** 2):.1f} MB"
else:
return f"{size / (1024 ** 3):.1f} GB"
def update_file_list(self, directory):
self.delete(*self.get_children())
try:
for entry in os.scandir(directory):
name = entry.name
if entry.is_file():
extension = os.path.splitext(name)[1]
date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(entry.stat().st_mtime))
size = self.format_file_size(entry.stat().st_size)
self.insert('', 'end', text=name, values=(extension, date, size, ''))
elif entry.is_dir():
self.insert('', 'end', text=name, values=('', '', '', ''))
except Exception as e:
print(f"Error scanning directory {directory}: {e}")
def on_file_open(self, event):
item = self.selection()[0]
path = self.item(item, "text")
if self.master.current_path != "This PC":
path = os.path.join(self.master.current_path, path)
if os.path.isdir(path):
self.master.current_path = path
self.master.update_file_list()
if __name__ == "__main__":
app = FileExplorer()
app.mainloop()