Python

 

 

 

 

Python - GUI - FileBrowser

 

In this note, I will show you a fully functioning file browser.

 

Why I want write this kind of file browser while Windows (the operating system) already provide a fancy working file browser? Yes, the operating systems come with their own file browsers. But sometimes, they don't meet our specific needs. Sometimes, I want a tool that we can adjust and integrate directly into our own applications and I want to have full control over it and modify the behavior / functionality as I like.

 

That's what I am talking about in this note. I've built a simple file browser using Python and the Tkinter library. This isn't just any file browser - you can embed this directly into your Python programs. You're in the driver's seat, controlling how it works and what it can do.

 

With this file browser, you can go through directories, rename files, copy and paste them, delete them, and even create new directories. We've made it easy to understand and modify, perfect if you want to include a customized file browser in your Python project.

 

 

 

Packages that I need

 

For learning purpose, let's first take a look at the list of packages (modules) that I am going to use in the program.

  • os: This is a built-in Python module that provides a way of using operating system dependent functionality. You can use it to read or write environment variables, manage files and directories, find out the user ID and more. This module is great for interacting with your system, making it a versatile tool for many Python projects.
  • tkinter: Tkinter is Python's standard graphical user interface (GUI) package. It is the most commonly used way of creating windows, dialogs, buttons, and all sorts of other elements that you'd typically see in a desktop application. If you've ever wanted to create an application with a graphical interface in Python, tkinter is likely the module you'll use.
  • ttk (tkinter.ttk): This is a submodule of tkinter. ttk stands for 'themed tkinter', which provides access to the Tk themed widget set. These widgets have a more modern and attractive look than the original tkinter widgets. They also automatically adjust to the platform's look and feel, making your applications more flexible and visually appealing.
  • messagebox (tkinter.messagebox): This is another submodule of tkinter. It provides a set of dialog boxes from the simple ones like warnings, errors, and information to the ones that ask questions to the users like 'yes/no' or 'ok/cancel'. This module is great for interacting with the user and getting their input during runtime.
  • simpledialog (tkinter.simpledialog): Yet another tkinter submodule, simpledialog allows you to have simple, yet flexible dialogs. You can ask for a string, an integer, or a float. While messagebox is great for getting simple user confirmation, simpledialog is the go-to module for when you need a specific response from the user.
  • shutil: This stands for 'shell utility' and is a built-in Python module used for high-level file operations. With shutil, you can copy, move, delete files, and a lot more. It is especially handy for operations involving multiple files, like copying all files with a certain extension from one directory to another.

 

 

 

Component overview

 

Now let's take a brief overview on various objects and their functionality that are used in the script. Try to understand this high level functionality and then go through the script. It would be much easier to understand the script.

  • os.path.join: This function is used to combine one or more path names into a single path. It's used throughout your script to create full file and directory paths.
  • os.listdir: This function returns a list containing the names of the entries in the directory given by path. This is used in the update_file_list function to get the contents of the current directory.
  • os.path.isdir: This function is used to check if a given path is an existing directory. It is used in the update_file_list and navigate functions to differentiate between files and directories.
  • os.path.isfile: Similar to os.path.isdir, this function checks if a given path is an existing regular file. It's used in the copy_file and delete_file functions.
  • os.path.basename and os.path.dirname: These functions are used to get the base name of the file or directory from the full path and to get the directory name from the full path respectively.
  • os.remove: This function is used to remove (delete) a file path. It's used in the delete_file function.
  • os.mkdir: This function is used to create a directory. It's used in the create_dir function.
  • os.rename: This function renames a file or directory, moving it if required. It's used in the rename_file function.
  • shutil.copy2: This function is similar to shutil.copy(), but it also attempts to preserve file metadata. It's used in the paste_file function.
  • shutil.rmtree: This function is used to delete an entire directory tree; a directory and all its contents. It's used in the delete_file function.
  • tkinter classes (tk.Frame, ttk.Button, ttk.Entry, ttk.Treeview, ttk.Scrollbar): These are all widget classes used to create various parts of the graphical user interface, including frames, buttons, text entry fields, treeviews (for the file list), and scrollbars.
  • tkinter functions (pack, bind, mainloop): These functions are used to manage the GUI, including packing widgets into their parent widget, binding functions to certain events (like pressing the Enter key or double-clicking), and starting the main event loop for the application.
    • pack: The pack method in Tkinter is one of the ways to organize and manage the geometry of the widgets. The method organizes widgets in blocks before placing them in the parent widget. It uses a packing algorithm to place widgets in available spaces. This method is quite simple to use and very effective for simple GUI layouts. (NOTE : Refer to this note on various types of layout manager).
    • bind: The bind method is used to bind a function to a specific event. For example, you might want a function to run when a user clicks a button, presses a key, or moves the mouse
    • mainloop: This is the method that you call to start the Tkinter event loop. This method will loop forever, waiting for events from the user, until the user closes the window. The event loop is an essential part of any graphical user interface, because it allows the program to respond to user input in real-time.
  • tkinter variables (tk.StringVar): This is a special variable class provided by tkinter. It's used in this script to manage the current directory path.
  • messagebox functions (showerror, askokcancel): These are used to display error messages and confirmation dialogs to the user.
  • simpledialog.askstring: This function pops up a dialog window and returns the string entered by the user. It's used in the create_dir function to get the name of the new directory.

 

 

 

Code and Outcome

 

Now let's dive into the source code. It would be helpful to understand the code if you have understanding on overall usage of the program.  One good approach would be just to run the script and use the program first according to the following instructions and then look into the source code. Followings are brief operation manual for this program.

 

Navigating Directories: Type the directory path you want to navigate to in the entry box at the top and press the "Navigate" button or the "Enter" key. You can also double-click on a directory in the file list to navigate to it. To move back up to the parent directory, double-click on the ' ..' entry at the top of the file list.

 

Renaming Files or Directories: To rename a file or directory, select it in the file list and press the "Rename" button. An entry box will appear in place of the item's name in the file list. Type the new name in the entry box and press the "Enter" key.

 

Copying and Pasting Files: To copy a file, select it in the file list and press the "Copy" button. Then navigate to the destination directory where you want to paste the file and press the "Paste" button. If a file with the same name already exists in the destination directory, the copied file will be renamed to avoid overwriting the existing file. You can copy / paste single file or multiple files.

 

Deleting Files or Directories: To delete a file or directory, select it in the file list and press the "Delete" button. A confirmation dialog will appear. If you confirm the deletion, the file or directory will be deleted. You can delete single file or multiple files.

 

Creating Directories: To create a new directory, press the "Create Dir" button. A dialog will appear asking for the name of the new directory. Type the name and press the "OK" button to create the directory.

 

 

Script (GUI_tkinter_FileBrowser.py)

import os

import tkinter as tk

from tkinter import ttk

from tkinter import messagebox

from tkinter import simpledialog

import shutil

 

 

# The whole program is implemented by a single class called FileBrowser in this program.

# The FileBrowser class is a custom tkinter frame that functions as a basic file browser. It inherits from tk.Frame,

# which means it can be used as a widget in a larger tkinter application, or as a standalone application. The class

# encapsulates all the necessary functionality for browsing files and directories, including viewing, navigating,

# renaming, copying, pasting, deleting, and creating directories. Followings are overall description of this class.

 #

# 1. Initialization: The class constructor (__init__) sets up the base frame, initializes the current path, and a list to

#    store copied file paths. It also loads icons to represent folders and files in the interface, calls a method to create

#    the interface widgets, and another one to populate the file list based on the current path.

 #

# 2. Widgets: The create_widgets method creates and packs all the necessary tkinter widgets to the frame. These

#     include an entry box and a button for navigating directories, buttons for file operations (rename, copy, paste,

#     delete, create directory), and a treeview with a scrollbar for listing files and directories.

#

# 3. File Operations: The class includes methods for each file operation. Each method generally works by first

#    determining which file or directory is currently selected in the treeview, then performs the operation using the

#    appropriate function from the os or shutil modules. After the operation, the file list is updated to reflect any

#    changes.

#

# 4. File List: The update_file_list method is used to refresh the file list based on the current directory. It first clears

#    the treeview, then uses os.listdir to get a list of files and directories in the current directory, and adds each one

#    to the treeview.

 #

# 5. Navigation: The navigate method is used to change the current directory. It is bound to the double-click event

#    of the treeview, so when a user double-clicks on a directory in the file list, this method changes the current

#    directory to the selected directory and updates the file list.

 #

# 6. Main Loop: As a tkinter application, the file browser runs in a main event loop, which is started by calling the

#    mainloop method on the tkinter root object. This is done in the main function, not in the FileBrowser class itself.

#    The mainloop continuously waits for events (like button clicks or key presses) and responds to them by calling

#    the appropriate methods.

#

class FileBrowser(tk.Frame):

    def __init__(self, master=None, path='C:\\'):

        super().__init__(master)

        self.path = path

        self.pack(fill='both', expand=True)

 

        self.paths_to_copy = []

 

        # Load the icons

        self.folder_icon = tk.PhotoImage(file="icon_dir.png")

        self.file_icon = tk.PhotoImage(file="icon_file.png")

 

        self.create_widgets()

        self.update_file_list()

 

 

# This function(method) sets up all the necessary graphical user interface (GUI) components, also known as

# "widgets", for the file browser application.

 #

# Firstly, it creates a navigation frame that includes an entry box for directory paths and a button to navigate to

# the input path. It also binds the Enter key to the update_file_list function, which updates the file list based on

# the entered path.

 #

# Next, it creates a button frame that houses a collection of buttons for file operations. These operations include

# renaming a file, copying a file, pasting a copied file, deleting a file, and creating a new directory. Each button is

# associated with its respective command.

 #

# Finally, it constructs a file frame that contains a treeview widget and a scrollbar. The treeview widget is used to

# display the list of files and directories in the current directory. It also binds the double-click event on a directory

# to the navigate function, which changes the current directory to the selected directory. The scrollbar is added to

# provide vertical navigation in the treeview when the list of files and directories is too long to fit in the window.

 #

# All the widgets are packed inside their respective frames using the pack method, which arranges them in their

# containers. This function is responsible for organizing the layout of the application and connecting the widgets

# with their corresponding functions.

#

    def create_widgets(self):

 

        self.navigation_frame = tk.Frame(self)  # Frame to hold the Entry and Button

        self.navigation_frame.pack(fill='x')

        self.directory = tk.StringVar(value=self.path)

 

        self.entry = ttk.Entry(self.navigation_frame, textvariable=self.directory)

        self.button = ttk.Button(self.navigation_frame, text="Navigate", command=self.update_file_list)

 

        self.entry.pack(side='left', fill='x', padx=[5,0], pady=[5,5], expand=True)

        self.button.pack(side='right',padx=[5,5])

 

        # Bind the Enter key to the update_file_list function

        self.entry.bind('<Return>', lambda event: self.update_file_list())

 

        # Creating button frame

        self.button_frame = tk.Frame(self)

        self.button_frame.pack(fill='x')

 

        self.rename_button = ttk.Button(self.button_frame, text="Rename", command=self.rename_file)

        self.copy_button = ttk.Button(self.button_frame, text="Copy", command=self.copy_file)

        self.paste_button = ttk.Button(self.button_frame, text="Paste", command=self.paste_file)

        self.delete_button = ttk.Button(self.button_frame, text="Delete", command=self.delete_file)

        self.create_dir_button = ttk.Button(self.button_frame, text="Create Dir", command=self.create_dir)

 

        self.rename_button.pack(side='left', padx=[5,0], pady=[0,5])

        self.copy_button.pack(side='left', pady=[0,5])

        self.paste_button.pack(side='left', pady=[0,5])

        self.delete_button.pack(side='left', pady=[0,5])

        self.create_dir_button.pack(side='left', padx=[0,5], pady=[0,5])

 

        self.file_frame = tk.Frame(self)  # Frame to hold the Treeview and Scrollbar

        self.file_frame.pack(fill='both', expand=True)

 

        self.file_list = ttk.Treeview(self.file_frame)

        self.file_list.heading('#0', text='File Name')

        self.file_list.bind('<Double-1>', self.navigate)  # Bind the function navigate to double click event

        self.file_list.tag_configure('parent_directory', font=('TkDefaultFont', 14, 'bold'))

 

        self.scrollbar = ttk.Scrollbar(self.file_frame, orient="vertical", command=self.file_list.yview)

        self.file_list.configure(yscrollcommand=self.scrollbar.set)

 

        # Use side option to pack Treeview and Scrollbar horizontally

        self.file_list.pack(side='left', fill='both', expand=True, padx=[5,0], pady=[0,5])

        self.scrollbar.pack(side='right', fill='y')

 

 

# This function is designed to rename a selected file or directory in the FileBrowser application.

 #

# The first step is to identify which file or directory has been selected in the application's treeview. This is done by

# calling self.file_list.selection()[0] to get the identifier for the selected item and self.file_list.item(selected_item,

# "text") to get the item's name.

 #

# Next, an inner function rename is defined to handle the renaming operation. This function fetches a new name

# provided by the user, constructs the old and new paths, and attempts to rename the file or directory at the old

# path to the new path. If the renaming is successful, the file list is updated. If an error occurs, the error message

# is printed out. After the operation, the temporary Entry widget used for input is destroyed.

 #

# The position of the selected item in the treeview is determined using self.file_list.bbox(selected_item). A new Entry

# widget is created at this position for the user to type the new name. The current name of the selected item is set

# as the initial value in the Entry widget, and focus is set on it to allow immediate typing.

 #

# Finally, the Enter key is bound to the rename function. This means that when the user hits the Enter key while the

# Entry widget is in focus, the rename function will be executed, renaming the selected item.

#

    def rename_file(self):

        # Get selected file or directory

        selected_item = self.file_list.selection()[0]

        selected_item_text = self.file_list.item(selected_item, "text")

 

        # Function to handle renaming

        def rename(event=None):

            new_name = new_name_var.get()

            old_path = os.path.join(self.path, selected_item_text)

            new_path = os.path.join(self.path, new_name)

 

            try:

                os.rename(old_path, new_path)

                self.update_file_list()

            except Exception as e:

                print(f"Error renaming file: {e}")

            finally:

                # Destroy the Entry widget when done

                new_name_entry.destroy()

 

        # Get the position of the selected item in the treeview

        x, y, _, _ = self.file_list.bbox(selected_item)

 

        # Create an Entry widget at the position of the selected item

        new_name_var = tk.StringVar()

        new_name_entry = ttk.Entry(self.file_list, textvariable=new_name_var)

        new_name_entry.place(x=x, y=y)

        new_name_var.set(selected_item_text)

        new_name_entry.focus()

 

        # Bind the Enter key to the rename function

        new_name_entry.bind('<Return>', rename)

 

 

# This function is designed to copy one or more selected files within the FileBrowser application.

#

# First, the list of files to copy, self.paths_to_copy, is cleared. This ensures that only the files selected during the

# current operation will be copied.

#

# Next, the function loops over the identifiers of all selected items in the treeview, which are obtained by calling

# self.file_list.selection(). For each selected item, its name is obtained and its full path is constructed by joining the

# current path of the FileBrowser and the item's name.

#

# Then, the function checks if the selected item is a file by calling os.path.isfile(full_path). If it is indeed a file, its

# path is added to the self.paths_to_copy list. If it is not a file (meaning it could be a directory), an error message

# is displayed using messagebox.showerror(), informing the user that only files can be copied.

#

# By the end of this function, self.paths_to_copy will contain the paths of all files that the user has selected to copy.

# The actual copying operation is not performed in this function; the paths are merely prepared to be used in another

#  function such as paste_file.

#

    def copy_file(self):

        # Clear the list of files to copy

        self.paths_to_copy = []

 

        # Get selected files

        for selected_item in self.file_list.selection():

            selected_item_text = self.file_list.item(selected_item, "text")

            full_path = os.path.join(self.path, selected_item_text)

 

            # If the selected item is a file, add its path to the list

            if os.path.isfile(full_path):

                self.paths_to_copy.append(full_path)

            else:

                messagebox.showerror("Error", "Please select only files to copy.")

 

 

# This function is designed to paste the files that have been previously selected for copying in the FileBrowser

# application.

#

# The function first checks if there are any files to copy by examining self.paths_to_copy. If this list is empty, it

# means that no files have been selected for copying and hence an error message is displayed using

# messagebox.showerror().

#

# If there are files to copy, the function enters a try block to handle any errors that may occur during the copying

# operation. Within this block, it iterates over each path in self.paths_to_copy.

#

# For each file to be copied, the function obtains the base name of the file (i.e., the file name without any directory

# components) using os.path.basename(). It then computes the full path of the new file by joining the current path

# of the FileBrowser and the base name.

#

# The function then checks whether a file with the same name already exists at the destination. If such a file exists,

# it modifies the base name by appending '-Copy' to it before the file extension, and then recomputes the full path.

#

# The function then uses shutil.copy2() to copy the file from the source path to the destination. This function is

# chosen over shutil.copy() because copy2() also copies the file's metadata (like its creation and modification times),

# not just its content.

#

# After all the files have been copied, the function clears the self.paths_to_copy list and updates the file list by

# calling self.update_file_list().

#

If any error occurs during the copying operation, an error message is displayed with the details of the error.

    def paste_file(self):

        # If there are files to copy

        if self.paths_to_copy:

            try:

                for path_to_copy in self.paths_to_copy:

                    # Get the base name of the file to copy

                    file_name = os.path.basename(path_to_copy)

                    # Compute the full path of the new file

                    new_file_path = os.path.join(self.path, file_name)

                    

                    # If a file with the same name already exists in the destination directory

                    if os.path.exists(new_file_path):

                        # Split the file name into name and extension

                        name, ext = os.path.splitext(file_name)

                        # Append '-Copy' to the name and reassemble the file name

                        new_file_name = f"{name}-Copy{ext}"

                        # Compute the full path of the new file

                        new_file_path = os.path.join(self.path, new_file_name)

                    

                    # Copy the file

                    shutil.copy2(path_to_copy, new_file_path)

                

                # Clear the list of files to copy

                self.paths_to_copy = []

                self.update_file_list()

            except Exception as e:

                messagebox.showerror("Error", f"Failed to paste files: {e}")

        else:

            messagebox.showerror("Error", "No files to paste.")

 

 

# This function is responsible for deleting selected files and directories in the FileBrowser application.

#

# Initially, the function fetches the selected items from the file list using self.file_list.selection(). If no items are

# selected, an error message is displayed using messagebox.showerror() and the function returns immediately.

#

# If some items are selected, the function then confirms whether the user wants to delete these items by showing

# a confirmation dialog using messagebox.askokcancel(). If the user confirms, the function starts a loop over the

# selected items.

#

# In each iteration, it fetches the text of the selected item and computes the full path of the item by joining the

# current path of the FileBrowser with the selected item's text.

#

# Then, the function checks if the item at the full path is a file or a directory. If it's a file, the file is deleted using

# os.remove(). If it's a directory, the function checks whether the directory is empty. If the directory is not empty,

# the user is asked for another confirmation before deleting the directory. If the user confirms, or if the directory is

# empty, the directory is deleted using shutil.rmtree(), which removes an entire directory tree, i.e., a directory and

# all its contents.

#

#After deleting each item, the file list is updated by calling self.update_file_list().

#

#If an error occurs during the deletion of any item, an error message is displayed with the details of the error.

#

    def delete_file(self):

        # Get selected items

        selected_items = self.file_list.selection()

 

        if not selected_items:

            messagebox.showerror("Error", "No file or directory selected.")

            return

 

        response = messagebox.askokcancel("Confirm delete", "Are you sure you want to delete the selected items?")

 

        if response:

            for selected_item in selected_items:

                selected_item_text = self.file_list.item(selected_item, "text")

                full_path = os.path.join(self.path, selected_item_text)

 

                try:

                    # If the selected item is a file, delete it

                    if os.path.isfile(full_path):

                        os.remove(full_path)

                    # If the selected item is a directory, delete it and all its contents

                    elif os.path.isdir(full_path):

                        # Check if directory is not empty

                        if os.listdir(full_path):

                            response = messagebox.askokcancel("Directory not empty",

                                                            "This directory is not empty. All the files within the directory will be deleted as well. Do you want to delete?")

                            if response:

                                shutil.rmtree(full_path)

                            else:

                                continue

                        else:

                            shutil.rmtree(full_path)

                    self.update_file_list()

                except Exception as e:

                    messagebox.showerror("Error", f"Failed to delete {selected_item_text}: {e}")

 

 

# This function is responsible for creating a new directory.

#

# Firstly, it opens a dialog asking the user to enter the name of the new directory using the simpledialog.askstring()

# function. The title of the dialog is "Create Directory" and the prompt is "Enter new directory name".

#

# If the user doesn't type a name and closes the dialog, the askstring() function returns None and the create_dir

# function just returns without doing anything.

#

# If the user types a name and clicks OK, the askstring() function returns the typed string and the create_dir

# function tries to create a directory with that name.

#

# The function computes the full path of the new directory by joining the current path of the FileBrowser with the

# new directory name. Then it tries to create the directory at this path using the os.mkdir() function.

#

# If the directory is successfully created, the function updates the file list by calling self.update_file_list(), so the

# new directory appears in the list.

#

# If an error occurs during the creation of the directory, the function catches the exception and shows an error

# message using messagebox.showerror(). The error message includes the name of the directory that failed to be

# created and the details of the error.

#

    def create_dir(self):

        # Show a dialog asking for the name of the new directory

        new_dir_name = simpledialog.askstring("Create Directory", "Enter new directory name")

 

        # If the user didn't type a name, return

        if not new_dir_name:

            return

 

        # Try to create the directory

        new_dir_path = os.path.join(self.path, new_dir_name)

        try:

            os.mkdir(new_dir_path)

            self.update_file_list()

        except Exception as e:

            messagebox.showerror("Error", f"Failed to create directory '{new_dir_name}': {e}")

 

 

# This function is a crucial part of the FileBrowser application, handling the task of refreshing the display of files

# and directories.

#

# Firstly, it fetches the current directory from the directory variable and clears the file_list Treeview of any existing

# entries.

#

# If the current path isn't the root directory (C:\\), it inserts a parent directory entry at the top of the list, denoted

# by '..'. This allows navigation back up the directory tree.

#

# The function then attempts to list the contents of the current directory using the os.listdir() function. If the

# directory doesn't exist (which may happen if it was manually deleted or moved outside of the FileBrowser

# application), os.listdir() raises a FileNotFoundError, which is caught and causes the function to return immediately.

#

# For existing directories, the function splits the contents into two separate lists: dirs for directories and files for files.

# This is done by iterating over each item in the directory, forming its full path by joining the item's name to the

# current path, and then checking if it's a directory or a file using os.path.isdir().

#

# Afterwards, it populates the file_list Treeview with the directories and files. The directories and files are inserted

# separately, ensuring that directories always appear before files. Each directory is displayed with a folder_icon and

# each file with a file_icon.

#

    def update_file_list(self):

        self.path = self.directory.get()

        self.file_list.delete(*self.file_list.get_children())

        if self.path != 'C:\\':

            #self.file_list.insert("", "end", text='..', open=False)

            self.file_list.insert("", "end", text='..', open=False, tags=('parent_directory',))

        try:

            dir_content = os.listdir(self.path)

        except FileNotFoundError:

            return

 

        dirs = []

        files = []

        for item in dir_content:

            item_full_path = os.path.join(self.path, item)

            if os.path.isdir(item_full_path):

                dirs.append(item)

            else:

                files.append(item)

 

        for dir in dirs:

            self.file_list.insert("", "end", text=dir, open=False, image=self.folder_icon)

        for file in files:

            self.file_list.insert("", "end", text=file, image=self.file_icon)

 

 

# This function is responsible for changing the current directory based on user's selection in the file browser.

#

# The function is bound to a double-click event on the file list, so it is triggered whenever the user double-clicks

# on a file or directory entry in the file list.

#

# When triggered, it first identifies the item that was double-clicked by calling self.file_list.selection()[0] to get the

# first selected item in the file list. It then retrieves the text of the selected item, which is the name of the file or

# directory.

#

# If the selected item is '..', representing the parent directory, the function uses os.path.dirname(self.path) to get

# the path of the parent directory. Otherwise, it uses os.path.join(self.path, selected_item_text) to form the full

# path of the selected directory.

#

# Next, it checks whether the new path exists using os.path.exists(new_path). This is a safeguard against trying to

# navigate to a directory that has been deleted or moved outside of the FileBrowser application.

#

# If the new path exists, it updates self.directory to the new path and calls self.update_file_list() to refresh the file

# list.

#

    def navigate(self, event):   # Function to navigate to the selected directory

        selected_item = self.file_list.selection()[0]

        selected_item_text = self.file_list.item(selected_item, "text")

        if selected_item_text == '..':

            new_path = os.path.dirname(self.path)

        else:

            new_path = os.path.join(self.path, selected_item_text)

        if os.path.exists(new_path):

            self.directory.set(new_path)

            self.update_file_list()

 

 

def main():

    root = tk.Tk()

    root.title("Simple File Browser")

    root.geometry("600x400")

    app = FileBrowser(master=root, path='C:\\')

    app.mainloop()

 

if __name__ == "__main__":

    main()

Result