Career Paths

The Desktop App Builder

Learn how to create desktop applications with a graphical user interface (GUI) using the built-in Tkinter library.

Our Project: Simple Notepad Application

We will create a functional Notepad-like application, with a window, text area, and a menu for opening and saving text files.

Core Technologies We'll Use:

Python
Tkinter
Step 1 / 6

Step 1: Introduction to Tkinter and Creating a Basic Window

We learn what Tkinter is and create our first empty application window.

What is Tkinter?

Tkinter is Python's standard (built-in) library for creating graphical user interfaces (GUIs). No additional installation is required. It allows you to create windows, buttons, text boxes, and other "widgets" to build interactive desktop applications.

Creating a Window

The basic structure of a Tkinter application includes:

  1. Importing the library: import tkinter as tk.
  2. Creating the main window (root window): window = tk.Tk().
  3. Adding a title and dimensions to the window.
  4. Starting the application's "main loop" with window.mainloop(). This loop "listens" for user actions (clicks, key presses) and keeps the window open.

Create a file notepad_app.py and add the following code.


# notepad_app.py
import tkinter as tk

# Δημιουργία του κύριου παραθύρου της εφαρμογής
window = tk.Tk()

# Ορισμός του τίτλου του παραθύρου
window.title("Απλό Σημειωματαριο")

# Ορισμός του αρχικού μεγέθους του παραθύρου (πλάτος x ύψος)
window.geometry("800x600")

# Έναρξη του κύριου βρόχου της εφαρμογής
# Αυτό κρατά το παράθυρο ανοιχτό και περιμένει ενέργειες χρήστη
window.mainloop()
Step 2 / 6

Step 2: Creating a Text Widget

We add the main widget of our application, a text area, where the user can write.

The most important widget for a notepad is, of course, the text area. In Tkinter, this is implemented with the tk.Text widget.

Adding the Text Widget

We will create a tk.Text object and "pack" it inside the main window. The .pack() method is one way to place widgets in the window. The arguments expand=True and fill="both" tell the text widget to expand and fill all available space, even when the user resizes the window.


# (Στο αρχείο notepad_app.py, πριν το window.mainloop())
import tkinter as tk

window = tk.Tk()
window.title("Απλό Σημειωματαριο")
window.geometry("800x600")

# Δημιουργία του Text widget
# Το πρώτο όρισμα 'window' λέει στο Tkinter ότι αυτό το widget ανήκει στο κύριο παράθυρο
text_area = tk.Text(window, wrap="word", font=("Arial", 12))

# Τοποθέτηση του widget στο παράθυρο
text_area.pack(expand=True, fill="both")

window.mainloop()
Step 3 / 6

Step 3: Organizing the Code into a Class

For better organization, we refactor our code into a class, a common practice for GUI applications.

As GUI applications grow, placing all the code in the main body of the script becomes unmanageable. Organizing the application within a class is a much better approach. By inheriting from tk.Tk, our class becomes the main window itself.


# (Αντικαταστήστε όλο το προηγούμενο περιεχόμενο του notepad_app.py)
import tkinter as tk

class NotepadApp(tk.Tk):
    def __init__(self):
        super().__init__() # Καλεί τον initializer της γονικής κλάσης (tk.Tk)
        
        self.title("Απλό Σημειωματαριο")
        self.geometry("800x600")

        self.text_area = tk.Text(self, wrap="word", font=("Arial", 12))
        self.text_area.pack(expand=True, fill="both")

# Εκκίνηση της εφαρμογής
if __name__ == "__main__":
    app = NotepadApp()
    app.mainloop()
Step 4 / 6

Step 4: Creating a Menu

We add a menu system at the top of the window with "File" and "Exit" options.

We will create a menu using the tk.Menu widget. The process is as follows:

  1. Create the main menu bar (main_menu) and associate it with the window.
  2. Create a submenu (file_menu) for file options.
  3. Add the file_menu to the main menu bar with the label "File" using .add_cascade().
  4. Add the commands ("New", "Open", "Save", "Exit") to the file_menu with .add_command(). For now, the "Exit" command will simply close the application by calling the self.quit method.

# (Μέσα στην κλάση NotepadApp, στη μέθοδο __init__)

# ... μετά τη γραμμή self.text_area.pack(...) ...

# Δημιουργία της κύριας μπάρας μενού
self.main_menu = tk.Menu(self)
self.config(menu=self.main_menu)

# Δημιουργία του μενού "Αρχείο"
self.file_menu = tk.Menu(self.main_menu, tearoff=False)
self.main_menu.add_cascade(label="Αρχείο", menu=self.file_menu)

# Προσθήκη επιλογών στο μενού "Αρχείο"
self.file_menu.add_command(label="Νέο") # Θα προσθέσουμε τη λειτουργία αργότερα
self.file_menu.add_command(label="Άνοιγμα...")
self.file_menu.add_command(label="Αποθήκευση ως...")
self.file_menu.add_separator() # Προσθέτει μια διαχωριστική γραμμή
self.file_menu.add_command(label="Έξοδος", command=self.quit)
Step 5 / 6

Step 5: Implementing File Operations (Open, Save)

We connect the menu options to functions that open dialog boxes for opening and saving files.

We will use Tkinter's filedialog module to display the familiar operating system dialog boxes. We will create new methods in our class (open_file, save_as_file) and connect them to the menu commands.

  • filedialog.askopenfilename(): Opens the "Open" dialog and returns the path of the selected file.
  • filedialog.asksaveasfilename(): Opens the "Save As" dialog and returns the path where the user wants to save the file.

Once we have the path, we use the familiar with open(...) logic to read or write the file content.


# (Στην αρχή του αρχείου notepad_app.py)
from tkinter import filedialog, messagebox
import os

# (Μέσα στην κλάση NotepadApp)
# ...
    def __init__(self):
        # ... (υπάρχων κώδικας)
        # Ενημέρωση των command του μενού
        self.file_menu.add_command(label="Νέο", command=self.new_file)
        self.file_menu.add_command(label="Άνοιγμα...", command=self.open_file)
        self.file_menu.add_command(label="Αποθήκευση ως...", command=self.save_as_file)
        # ...

    def new_file(self):
        if messagebox.askyesno("Νέο Αρχείο", "Είστε σίγουροι; Οι αλλαγές θα χαθούν."):
            self.text_area.delete("1.0", tk.END)
            self.title("Ανώνυμο - Απλό Σημειωματαριο")

    def open_file(self):
        file_path = filedialog.askopenfilename(defaultextension=".txt")
        if not file_path: return
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                self.text_area.delete("1.0", tk.END)
                self.text_area.insert("1.0", f.read())
            self.title(f"{os.path.basename(file_path)} - Απλό Σημειωματαριο")
        except Exception as e:
            messagebox.showerror("Σφάλμα", f"Δεν ήταν δυνατό το άνοιγμα του αρχείου: {e}")

    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(defaultextension=".txt")
        if not file_path: return
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                content = self.text_area.get("1.0", tk.END)
                f.write(content)
            self.title(f"{os.path.basename(file_path)} - Απλό Σημειωματαριο")
        except Exception as e:
            messagebox.showerror("Σφάλμα", f"Δεν ήταν δυνατή η αποθήκευση του αρχείου: {e}")
Step 6 / 6

Step 6: Adding a Status Bar

We complete our application by adding a status bar at the bottom that will display useful information, such as the word count.

A status bar is a common element in many applications. We will use a tk.Label widget for this purpose. The key here is to make the bar update automatically as the user types. We achieve this by "binding" a method to the Text widget's virtual event <<Modified>>. Whenever the content changes, our method (update_status) will be called automatically.


# (Μέσα στην __init__ της κλάσης NotepadApp)
# ...
        # ... μετά την προσθήκη του μενού ...
        
        # Δημιουργία της μπάρας κατάστασης
        self.status_bar = tk.Label(self, text="Έτοιμο", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        
        # Σύνδεση της μεθόδου ενημέρωσης με το συμβάν τροποποίησης του κειμένου
        self.text_area.bind("<<Modified>>", self.update_status)

# (Προσθήκη νέας μεθόδου στην κλάση NotepadApp)
    def update_status(self, event=None):
        content = self.text_area.get("1.0", "end-1c") # Λήψη όλου του κειμένου
        word_count = len(content.split())
        char_count = len(content)
        self.status_bar.config(text=f"Λέξεις: {word_count} | Χαρακτήρες: {char_count}")
        # Σημαντικό: Επαναφέρουμε την κατάσταση "modified" σε false για να μην καλείται συνεχώς
        self.text_area.edit_modified(False)

Project Completion & Next Steps

Congratulations! You have completed the path and now have the full code for the project.

This is the final, complete code for the application. You can copy it, run it locally on your computer (after installing the necessary libraries with `pip`), and experiment by adding your own features!


# notepad_app.py
import tkinter as tk
from tkinter import filedialog, messagebox
import os

class NotepadApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Απλό Σημειωματαριο")
        self.geometry("800x600")

        self.text_area = tk.Text(self, wrap="word", font=("Arial", 12))
        self.text_area.pack(expand=True, fill="both")

        self.main_menu = tk.Menu(self)
        self.config(menu=self.main_menu)

        self.file_menu = tk.Menu(self.main_menu, tearoff=False)
        self.main_menu.add_cascade(label="Αρχείο", menu=self.file_menu)
        self.file_menu.add_command(label="Νέο", command=self.new_file)
        self.file_menu.add_command(label="Άνοιγμα...", command=self.open_file)
        self.file_menu.add_command(label="Αποθήκευση ως...", command=self.save_as_file)
        self.file_menu.add_separator()
        self.file_menu.add_command(label="Έξοδος", command=self.quit)
        
        self.status_bar = tk.Label(self, text="Έτοιμο", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
        self.text_area.bind("<<Modified>>", self.update_status)
    
    def update_status(self, event=None):
        content = self.text_area.get("1.0", "end-1c")
        word_count = len(content.split())
        char_count = len(content)
        self.status_bar.config(text=f"Λέξεις: {word_count} | Χαρακτήρες: {char_count}")
        self.text_area.edit_modified(False)

    def new_file(self):
        if messagebox.askyesno("Νέο Αρχείο", "Είστε σίγουροι; Οι αλλαγές θα χαθούν."):
            self.text_area.delete("1.0", tk.END)
            self.title("Ανώνυμο - Απλό Σημειωματαριο")

    def open_file(self):
        file_path = filedialog.askopenfilename(
            defaultextension=".txt",
            filetypes=[("Αρχεία Κειμένου", "*.txt"), ("Όλα τα αρχεία", "*.*")]
        )
        if not file_path:
            return
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                self.text_area.delete("1.0", tk.END)
                self.text_area.insert("1.0", f.read())
            self.title(f"{os.path.basename(file_path)} - Απλό Σημειωματαριο")
        except Exception as e:
            messagebox.showerror("Σφάλμα", f"Δεν ήταν δυνατό το άνοιγμα του αρχείου:\n{e}")

    def save_as_file(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("Αρχεία Κειμένου", "*.txt"), ("Όλα τα αρχεία", "*.*")]
        )
        if not file_path:
            return
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                content = self.text_area.get("1.0", tk.END)
                f.write(content)
            self.title(f"{os.path.basename(file_path)} - Απλό Σημειωματαριο")
        except Exception as e:
            messagebox.showerror("Σφάλμα", f"Δεν ήταν δυνατή η αποθήκευση του αρχείου:\n{e}")

if __name__ == "__main__":
    app = NotepadApp()
    app.mainloop()