πŸ‡―πŸ‡΅ ζ—₯本θͺž | πŸ‡ΊπŸ‡Έ English | πŸ‡ͺπŸ‡Έ EspaΓ±ol | πŸ‡΅πŸ‡Ή PortuguΓͺs | πŸ‡ΉπŸ‡­ ΰΉ„ΰΈ—ΰΈ’ | πŸ‡¨πŸ‡³ δΈ­ζ–‡

[Copy-Paste Ready] Let's Build a Simple Notepad App with Python! (With File Saving)

"I want to try building something tangible with programming!"

If that's you, then you've come to the right place. In this article, I'll explain, in the simplest way possible, how to create your very own simple "Notepad app" where you can type text and save it to a file using the Python programming language.

Hello! I'm a self-taught web developer who, with the help of AI, started from zero programming knowledge just a few months ago. At first, I was at a level where I thought, "File saving? Is that some kind of magic spell?" (lol). That's precisely why I want to avoid jargon as much as possible and walk you through this, sharing the points where I stumbled as a fellow beginner.

The goal of this article is simple: to let you experience the thrill of "my own program is working!". To do that, we'll save the difficult stuff for later! First, let's copy, paste, and play with the finished product.


STEP 1: Let's Run It Right Away! Here's the Complete Code

Seeing is believing. First, copy all the code below, save it as memo_app.py, and try running it. If you don't have a Python environment set up, please prepare that first.

If you're thinking, "Wait, the finished code already?" or "Where's the explanation?", you're on the right track! Experiencing that "it works" moment first is the secret to making programming fun.


import tkinter as tk
import tkinter.filedialog as filedialog

def save_file():
    """Function to save a file"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        print(f"An error occurred: {e}")

def open_file():
    """Function to open a file"""
    file_path = filedialog.askopenfilename(
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            text_content = file.read()
            text_area.delete(1.0, tk.END)
            text_area.insert(tk.END, text_content)
    except Exception as e:
        print(f"An error occurred: {e}")

# Create the main window
window = tk.Tk()
window.title("Simple Notepad")
window.geometry("600x400")

# Create the text input area
text_area = tk.Text(window, wrap=tk.WORD)
text_area.pack(expand=True, fill=tk.BOTH)

# Create the menu bar
menu_bar = tk.Menu(window)
window.config(menu=menu_bar)

# Create the "File" menu
file_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="Open...", command=open_file)
file_menu.add_command(label="Save As...", command=save_file)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=window.quit)

# Display the window
window.mainloop()
    

How did it go? If you see a window like this, it's a huge success!

A screenshot of a simple notepad app created with Python. There is a 'File' menu at the top of the window and a large text input area in the center.

Try typing some text or selecting "Save As..." or "Open..." from the menu. Isn't it a little exciting that it actually functions as a notepad?


STEP 2: Exploring the Code! Let's Peek at How It Works

Now that you've experienced the "it works!" moment, let's explore "why does it work?". We'll break down the code from before into parts and explain the role of each one.

β‘  Preparing the Magic Toolbox (import)

The first two lines of the code are like a magic spell to load the "handy tools" we're going to use into Python.


import tkinter as tk
import tkinter.filedialog as filedialog
    

β‘‘ Building the App's Foundation (Window Creation)

Next, we create the main window for our app. In home-building terms, this is like the foundation and framework.


# Create the main window
window = tk.Tk()
window.title("Simple Notepad")
window.geometry("600x400")

# ... (code omitted) ...

# Display the window
window.mainloop()
    

β‘’ Preparing a Place to Write (Text Area)

It's a notepad, so of course, we need a space to type text. This is the part that creates it.


# Create the text input area
text_area = tk.Text(window, wrap=tk.WORD)
text_area.pack(expand=True, fill=tk.BOTH)
    

β‘£ Creating Boxes of Commands (Functions)

Finally, we get to the heart of this app: the specific processes for "Open File" and "Save File." These processes are defined as functions, which are like "handy boxes that group commands together."

Saving a File: The `save_file()` Function


def save_file():
    """Function to save a file"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        print(f"An error occurred: {e}")
    

This code is packed with important points.

  1. `filedialog.asksaveasfilename(...)`: This is the command that displays the "Save As" dialog box. The path of the save location chosen by the user (like an address leading to the filename) is stored in a variable called `file_path`.
  2. `if not file_path: return`: If the user clicks "Cancel" in the dialog, `file_path` will be empty. This is a crucial line that simply exits the function without doing anything in that case.
  3. `with open(file_path, 'w', encoding='utf-8') as file:`: This is the key to file I/O!
    • `open()`: A command to open the file at the specified path in the specified mode.
    • `'w'`: Stands for `write` mode. If the file doesn't exist, it's created. If it does, it's overwritten.
    • `encoding='utf-8'`: A super important magic spell to prevent garbled text. It specifies "UTF-8," a standard character encoding that can correctly handle most languages in the world. Without this, non-English characters might not be saved correctly.
    • `with ... as file:`: Using this syntax ensures that the file is automatically closed after the code block finishes. Forgetting to close a file can cause issues like memory leaks, so this is a very safe and recommended way of writing code. (Also recommended in the official documentation)
  4. `text_area.get(1.0, tk.END)`: This gets all the text currently in the text area.
  5. `file.write(text_content)`: This writes the retrieved text to the opened file.

Similarly, the `open_file()` function just uses `'r'` (read mode) to read the contents of a file and display them in the text area. The mechanism is almost identical!


STEP 3: Advanced Edition! Let's Customize Your Notepad

Now that you understand the basic mechanics, let's make it more interesting! You can implement useful features just by adding a little bit of code.

Customization 1: Create a Dark Mode-style Design

Dark mode is all the rage these days. Let's change the design to be easier on the eyes. You just need to specify the background and foreground colors where you create the `window` and `text_area`.


# Create the main window
window = tk.Tk()
window.title("Dark Notepad")
window.geometry("600x400")
window.config(bg="#2d2d2d") # Add the window background color

# Create the text input area
text_area = tk.Text(
    window, 
    wrap=tk.WORD,
    bg="#1e1e1e",          # Text area background color
    fg="#dcdcdc",          # Text color
    insertbackground="#ffffff" # Cursor color
)
text_area.pack(expand=True, fill=tk.BOTH)
    

Just with this, it has a much more modern feel, doesn't it?


Customization 2: Add Keyboard Shortcuts

Opening the menu every time is a hassle, right? Let's make it so you can save with "Ctrl + S" and open with "Ctrl + O". When adding items to the menu, we'll specify the shortcut with `accelerator` and then use `window.bind` to connect the actual key press to the function.

First, change the menu creation part like this:


# Create the "File" menu
file_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="File", menu=file_menu)
# Use accelerator to display a hint for the shortcut
file_menu.add_command(label="Open...", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="Save As...", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=window.quit)
    

Next, add the code to bind the key presses to the functions right before `window.mainloop()`.


# Bind keyboard shortcuts
# Use lambda to handle the event argument
window.bind("<Control-s>", lambda event: save_file())
window.bind("<Control-o>", lambda event: open_file())

# Display the window
window.mainloop()
    

The `bind` method calls a function when an event occurs (in this case, a key press), and when it does, it passes information about the event (the `event` object) as an argument. However, our `save_file` and `open_file` functions aren't designed to accept arguments. So, by using `lambda event:`, we're creating an intermediary that ignores the argument and calls our desired function. It's a neat little trick!


Things to Watch Out For (A Word of Caution)

File operations are a common source of unexpected errors. I also stared at error screens and held my head in my hands many times at first... Just knowing about the common errors can help you avoid panicking.

In our code, we use a `try...except` block to catch errors, so even if an error occurs, the app won't crash, and an error message will be displayed in the console. This is another important technique for building robust programs.


Conclusion: A Small Success is a Big Step Forward

Great work! In this article, we used Python's `Tkinter` to create a simple notepad app with a file-saving feature.

Were you able to experience starting from copy-paste, understanding the mechanism, and finally customizing it yourself? The experience of "seeing code I wrote work in a visible way" is a joy like no other and is the best motivation for continuing to learn programming.

The app we built today is just the beginning. You can add countless features depending on your ideas, like a search function, word count, or auto-save. Please use this article as a foundation and try to develop your very own original app!

On to the Next Step

Now that you've grasped the basics of GUI apps, why not try manipulating "time" next? In the next article, we'll explain how to use Python's `time` module to create a timer app that notifies you at a specified time. Let's challenge ourselves to build useful everyday tools like alarms and Pomodoro timers!

β†’ Let's Make a Timer App with Python (time module)

Bonus: The Complete, Ready-to-Run Python Code

Here is the final, complete Python code that incorporates all the examples discussed in this article, including the dark-mode style design and keyboard shortcuts. Just copy and paste this, and you'll have a feature-rich notepad app ready to use instantly!

<?php
/*
This is a Python script, not a PHP file to be run on a web server.
Please change the extension to .py and run it with a Python interpreter.
Example: python your_file_name.py
*/
?>
import tkinter as tk
import tkinter.filedialog as filedialog

def save_file():
    """Function to save the file"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        # Ideally, you'd log this or notify the user with a dialog
        print(f"An error occurred: {e}")
        window.title(f"Error: {e}")


def open_file():
    """Function to open a file"""
    file_path = filedialog.askopenfilename(
        filetypes=[("Text Files", "*.txt"), ("All Files", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            text_content = file.read()
            text_area.delete(1.0, tk.END)
            text_area.insert(tk.END, text_content)
            window.title(f"Notepad - {file_path}")
    except Exception as e:
        print(f"An error occurred: {e}")
        window.title(f"Error: {e}")


# --- GUI Setup ---

# Create the main window
window = tk.Tk()
window.title("Enhanced Notepad")
window.geometry("800x600")
window.config(bg="#2d2d2d") # Window background color

# Create the text input area
text_area = tk.Text(
    window,
    wrap=tk.WORD,
    bg="#1e1e1e",          # Text area background color
    fg="#dcdcdc",          # Text color
    insertbackground="#ffffff", # Cursor color (white for visibility)
    undo=True,             # Enable Undo/Redo
    autoseparators=True
)
text_area.pack(expand=True, fill=tk.BOTH, padx=5, pady=5)


# Create the menu bar
menu_bar = tk.Menu(window)
window.config(menu=menu_bar)

# Create the "File" menu
file_menu = tk.Menu(menu_bar, tearoff=0, bg="#2d2d2d", fg="#dcdcdc")
menu_bar.add_cascade(label="File", menu=file_menu)
file_menu.add_command(label="Open...", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="Save As...", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="Exit", command=window.quit)

# Bind keyboard shortcuts (using lambda to ignore the event argument)
window.bind("<Control-s>", lambda event: save_file())
window.bind("<Control-o>", lambda event: open_file())
window.bind("<Control-S>", lambda event: save_file()) # Also handle Shift+S
window.bind("<Control-O>", lambda event: open_file()) # Also handle Shift+O

# Start the window's main event loop
window.mainloop()