[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!
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
- `tkinter`: This is a standard Python library for easily creating GUIs (Graphical User Interfaces) like windows and buttons. Think of it as the toolbox for building the skeleton and parts of your app.
- `tkinter.filedialog`: This is a specialized tool for displaying familiar dialog boxes like "Open File" and "Save As".
β‘ 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()
- `window = tk.Tk()`: This is the command that creates the window itself. It means, "Using the `Tk()` blueprint from the `tk` toolbox, create a window named `window`."
- `window.title(...)`: This sets the text that appears in the window's title bar.
- `window.geometry("600x400")`: This sets the initial size of the window to "600 pixels wide by 400 pixels high".
- `window.mainloop()`: This is the most important part! It's the command that displays the created window and keeps it running until the user closes it. Without this, the program would start and finish in an instant, and you'd never even see the window.
β’ 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)
- `text_area = tk.Text(...)`: We use a component (called a widget) named `Text` from the `tk` toolbox to create the text input area. `wrap=tk.WORD` is a setting that wraps lines at word boundaries, a nice touch to prevent awkward breaks in the middle of English words.
- `text_area.pack(...)`: This command places the created `text_area` into its parent, the `window`. `pack` is a simple layout method, and by specifying `expand=True, fill=tk.BOTH`, you get a smart layout where "if the window size changes, the text area will also expand to fill it up, down, left, and right."
β£ 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.
- `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`.
- `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.
- `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)
- `text_area.get(1.0, tk.END)`: This gets all the text currently in the text area.
- `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.
- `PermissionError`: This occurs if you try to save to a write-protected folder (e.g., `C:\Program Files`). Choose a location where you have write permissions, like your Desktop or Documents folder.
- `FileNotFoundError`: This happens in the `open_file` function if you specify a file that doesn't exist. Since our code uses `filedialog`, this generally won't happen, but it's something to be aware of if you modify the code.
- `UnicodeDecodeError`: This occurs if you try to open a file that can't be read with `encoding='utf-8'` (e.g., an old text file saved with `Shift_JIS`). This is a very deep issue, but for now, it's enough to just know that "there are many different character encodings in the world."
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()