Create Sticky Notes in Python using Tkinter

Faraz

By Faraz - July 03, 2024

Learn how to create sticky notes in Python using Tkinter with this step-by-step guide. Perfect for beginners looking to enhance their programming skills.


create-sticky-notes-in-python-using-tkinter.webp

Table of Contents

  1. Introduction to Tkinter
  2. Setting Up the Environment
  3. The Sticky Notes Application
  4. Creating the Sticky Notes Interface
  5. Features Implementation
  6. Running the Application
  7. Full Sticky Notes Source Code
  8. Conclusion

Sticky notes are a great tool for keeping track of small bits of information, reminders, and quick notes. With the Tkinter library in Python, you can create a desktop application that mimics the functionality of physical sticky notes. In this blog, we will walk through the steps of creating a sticky notes application using Tkinter, complete with various features such as saving, loading, and customizing notes.

Introduction to Tkinter

Tkinter is the standard GUI (Graphical User Interface) library for Python. It provides a fast and easy way to create GUI applications. Tkinter comes bundled with Python, which means you don't need to install anything extra to use it.

Setting Up the Environment

To get started, ensure you have Python installed on your computer. Tkinter is included with most Python installations, so you won't need to install it separately. Open your terminal or command prompt and verify your Python version with:

python --version

If Python is not installed, download it from the official Python website. Additionally, you can use a text editor or an integrated development environment (IDE) like Visual Studio Code or PyCharm to write your code.

The Sticky Notes Application

Our sticky notes application will have the following features:

  1. Create New Note: Allows the user to create a new sticky note.
  2. Save Note: Save the contents of a note to a file.
  3. Load Note: Load the contents of a note from a file.
  4. Change Font: Change the font of the note text.
  5. Change Background Color: Change the background color of the note.
  6. Minimize Note: Minimize the note window.
  7. Close Note: Close the note window with a confirmation dialog.

Creating the Sticky Notes Interface

Importing Modules

import tkinter as tk
from tkinter import Toplevel, Frame, X, TOP, Label, RIGHT, LEFT, BOTH, Tk, Menu, font, filedialog, colorchooser, simpledialog, messagebox
import tkinter.scrolledtext as tkst

We start by importing the necessary modules from Tkinter. tkinter.scrolledtext is imported as tkst to add a scrollable text area in our sticky notes.

Global Variables

no_of_windows = 1
notes = []  # to keep track of all open notes
  • We declare two global variables: no_of_windows to keep track of the number of open notes and notes to store the references to all open notes.

StickyNotes Class

class StickyNotes(Toplevel):
    ...

We create a class StickyNotes that inherits from Toplevel, which is a Tkinter widget used to create a new window.

Initializing the StickyNotes Class

def __init__(self, master, **kwargs):
    super().__init__(master, **kwargs)
    ...

In the __init__ method, we initialize the sticky note window with various attributes and configurations.

Title Bar

self.titlebar = Frame(self, bg='#FFFF00', relief='flat', bd=2)
self.titlebar.bind('<Button-1>', self.get_pos)
self.titlebar.bind('<B1-Motion>', self.move_window)
self.titlebar.pack(fill=X, expand=1, side=TOP)

We create a title bar for the sticky note with buttons for closing, minimizing, and creating a new note.

Main Text Area

self.mainarea = tkst.ScrolledText(self, bg='#FFFFA5', font=('Comic Sans MS', 14, 'italic'), relief='flat', padx=5, pady=10)
self.mainarea.pack(fill=BOTH, expand=1)

We added a scrollable text area where users can type their notes.

Context Menu

self.mainarea.bind("<Button-3>", self.show_context_menu)

We bind the right-click event to show a context menu with options to change the font, change the background color, save the note, and load a note.

Features Implementation

Move Window

def get_pos(self, event):
    self.xclick = event.x
    self.yclick = event.y

def move_window(self, event):
    self.geometry('+{0}+{1}'.format(event.x_root - self.xclick, event.y_root - self.yclick))

We implement methods to move the window by clicking and dragging the title bar.

Create New Note

def another_window(self, event):
    StickyNotes(root)

We create a method to open a new sticky note window.

Close Note

def quit_window(self, event):
    ...

We implement a method to close the note window with a confirmation dialog.

Minimize Note

def minimize_window(self, event):
    ...

We add a method to minimize and restore the note window.

Context Menu Options

def show_context_menu(self, event):
    context_menu = Menu(self, tearoff=0)
    context_menu.add_command(label="Change Font", command=self.change_font)
    context_menu.add_command(label="Change Background Color", command=self.change_bg_color)
    context_menu.add_command(label="Save Note", command=self.save_note)
    context_menu.add_command(label="Load Note", command=self.load_note)
    context_menu.post(event.x_root, event.y_root)

We create a context menu with options to change the font, change the background color, save the note, and load a note.

Change Font

def change_font(self):
    new_font = simpledialog.askstring("Change Font", "Enter font (e.g., Arial, 12):")
    if new_font:
        font_name, font_size = new_font.split(',')
        self.mainarea.config(font=(font_name.strip(), int(font_size.strip())))

We implement a method to change the font of the text area.

Change Background Color

def change_bg_color(self):
    color = colorchooser.askcolor()[1]
    if color:
        self.mainarea.config(bg=color)

We add a method to change the background color of the text area.

Save Note

def save_note(self):
    if self.filepath is None:
        self.filepath = filedialog.asksaveasfilename(defaultextension=".txt",
                                                     filetypes=[("Text files", "*.txt"), ("All files", "*.*")])

    if self.filepath:
        with open(self.filepath, "w") as f:
            f.write(self.mainarea.get("1.0", tk.END))

We create a method to save the note content to a file.

Load Note

def load_note(self):
    self.filepath = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("All files", "*.*")])
    if self.filepath:
        with open(self.filepath, "r") as f:
            self.mainarea.delete("1.0", tk.END)
            self.mainarea.insert("1.0", f.read())
We implement a method to load note content from a file.

Running the Application

root = Tk()
root.withdraw()
def on_closing():
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        for note in notes:
            note.on_closing()
        root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)

sticky = StickyNotes(root)
root.mainloop()

Finally, we initialize the main Tkinter window, set up the protocol for closing the application, and create the first sticky note window.

Full Sticky Notes Source Code

import tkinter as tk
from tkinter import Toplevel, Frame, X, TOP, Label, RIGHT, LEFT, BOTH, Tk, Menu, font, filedialog, colorchooser, simpledialog, messagebox
import tkinter.scrolledtext as tkst


no_of_windows = 1
notes = []  # to keep track of all open notes

class StickyNotes(Toplevel):
    def __init__(self, master, **kwargs):
        super().__init__(master, **kwargs)
        self.xclick = 0
        self.yclick = 0
        self.minimized = False
        self.filepath = None

        # master (root) window
        self.overrideredirect(True)
        global no_of_windows
        self.geometry('350x450+' + str(1000 + no_of_windows * (-30)) + '+' + str(100 + no_of_windows * 20))
        self.config(bg='#838383')
        self.attributes('-topmost', 'true')
        self.resizable(True, True)
        self.custom_font = font.Font(size=15)

        # titlebar
        self.titlebar = Frame(self, bg='#FFFF00', relief='flat', bd=2)
        self.titlebar.bind('<Button-1>', self.get_pos)
        self.titlebar.bind('<B1-Motion>', self.move_window)
        self.titlebar.pack(fill=X, expand=1, side=TOP)

        self.closebutton = Label(self.titlebar, text='X', bg='#FFFF00', relief='flat', cursor='hand2', font=self.custom_font)
        self.closebutton.bind('<Button-1>', self.quit_window)
        self.closebutton.pack(side=RIGHT)

        self.minbutton = Label(self.titlebar, text='-', bg='#FFFF00', relief='flat', cursor='hand2', width=2, font=self.custom_font)
        self.minbutton.bind('<Button-1>', self.minimize_window)
        self.minbutton.pack(side=RIGHT)

        self.newbutton = Label(self.titlebar, text='+', bg='#FFFF00', relief='flat', cursor='hand2', font=self.custom_font)
        self.newbutton.pack(side=LEFT)
        self.newbutton.bind('<Button-1>', self.another_window)

        self.mainarea = tkst.ScrolledText(self, bg='#FFFFA5', font=('Comic Sans MS', 14, 'italic'), relief='flat', padx=5, pady=10)
        self.mainarea.pack(fill=BOTH, expand=1)

        self.mainarea.bind("<Button-3>", self.show_context_menu)

        no_of_windows += 1
        notes.append(self)

    def get_pos(self, event):
        self.xclick = event.x
        self.yclick = event.y

    def move_window(self, event):
        self.geometry('+{0}+{1}'.format(event.x_root - self.xclick, event.y_root - self.yclick))

    def another_window(self, event):
        StickyNotes(root)

    def quit_window(self, event):
        self.closebutton.config(relief='flat', bd=0)
        if messagebox.askyesno('Delete Note?', 'Are you sure you want to delete this note?', parent=self):
            global no_of_windows
            self.destroy()
            notes.remove(self)
            no_of_windows -= 1
            if no_of_windows == 1:
                root.destroy()
            return
        self.closebutton.config(relief='flat', bd=0, bg='#F8F7B6')

    def minimize_window(self, event):
        if not self.minimized:
            self.mainarea.pack_forget()
            self.geometry("350x30")
            self.minimized = True
        else:
            self.mainarea.pack(fill=BOTH, expand=1)
            self.geometry("350x450")
            self.minimized = False

    def show_context_menu(self, event):
        context_menu = Menu(self, tearoff=0)
        context_menu.add_command(label="Change Font", command=self.change_font)
        context_menu.add_command(label="Change Background Color", command=self.change_bg_color)
        context_menu.add_command(label="Save Note", command=self.save_note)
        context_menu.add_command(label="Load Note", command=self.load_note)
        context_menu.post(event.x_root, event.y_root)

    def change_font(self):
        new_font = simpledialog.askstring("Change Font", "Enter font (e.g., Arial, 12):")
        if new_font:
            font_name, font_size = new_font.split(',')
            self.mainarea.config(font=(font_name.strip(), int(font_size.strip())))

    def change_bg_color(self):
        color = colorchooser.askcolor()[1]
        if color:
            self.mainarea.config(bg=color)

    def save_note(self):
        if self.filepath is None:
            self.filepath = filedialog.asksaveasfilename(defaultextension=".txt",
                                                         filetypes=[("Text files", "*.txt"), ("All files", "*.*")])
        if self.filepath:
            with open(self.filepath, "w") as f:
                f.write(self.mainarea.get("1.0", tk.END))

    def load_note(self):
        self.filepath = filedialog.askopenfilename(filetypes=[("Text files", "*.txt"), ("All files", "*.*")])
        if self.filepath:
            with open(self.filepath, "r") as f:
                self.mainarea.delete("1.0", tk.END)
                self.mainarea.insert("1.0", f.read())

    def on_closing(self):
        if messagebox.askokcancel("Quit", "Do you want to quit?"):
            global no_of_windows
            no_of_windows -= 1
            self.destroy()
            if no_of_windows == 1:
                root.destroy()


root = Tk()
root.withdraw()

def on_closing():
    if messagebox.askokcancel("Quit", "Do you want to quit?"):
        for note in notes:
            note.on_closing()
        root.destroy()

root.protocol("WM_DELETE_WINDOW", on_closing)

sticky = StickyNotes(root)
root.mainloop()

Conclusion

In this blog, we have created a sticky notes application using Python's Tkinter library. This application allows users to create, save, load, and customize sticky notes with various features. Tkinter makes it easy to create GUI applications, and with a little bit of code, you can build useful tools like this sticky notes app. Feel free to extend the functionality further and customize it to suit your needs.

That’s a wrap!

I hope you enjoyed this article

Did you like it? Let me know in the comments below 🔥 and you can support me by buying me a coffee.

And don’t forget to sign up to our email newsletter so you can get useful content like this sent right to your inbox!

Thanks!
Faraz 😊

End of the article

Subscribe to my Newsletter

Get the latest posts delivered right to your inbox


Latest Post