CodingNic

Final Capstone Project

GUI Setup, Theme, and Login Screen

Final Capstone Project 60 min read

GUI Setup, Theme, and Login Screen

GUI Setup, Theme, and Login Screen

Now you will begin building the graphical interface for your application.

Until now, everything has been backend logic.

In this lesson, you will:

  • create the main window
  • define a reusable theme (colors and fonts)
  • build a polished login screen using a centered card
  • prepare the structure for the dashboard (next lesson)

You are not connecting logic yet — only building structure.


Goal of This Lesson

By the end of this lesson, you will:

  • create a Tkinter window with a clean background
  • define a theme dictionary and font constants
  • build a styled button helper
  • build a centered login card with input fields and action buttons

Step 1: Create GUI File

Create:

text
app/ui/app_ui.py

Step 2: Import Tkinter

python
import tkinter as tk

Step 3: Define the Theme

A real application uses consistent colors and fonts everywhere.

Instead of repeating color values, store them in one place.

Add at the top of app_ui.py:

python
THEME = {
    "bg":            "#f3f4f6",   # window background (light grey)
    "card":          "#ffffff",   # card / panel background
    "border":        "#e5e7eb",   # subtle borders
    "text":          "#111827",   # primary text
    "muted":         "#6b7280",   # secondary text
    "primary":       "#2563eb",   # blue (primary action)
    "success":       "#16a34a",   # green (positive action)
    "danger":        "#dc2626",   # red (destructive action)
}

FONT_TITLE = ("Segoe UI", 22, "bold")
FONT_HEAD  = ("Segoe UI", 14, "bold")
FONT_LABEL = ("Segoe UI", 10)
FONT_BTN   = ("Segoe UI", 10, "bold")

Why a Theme Dictionary?

  • one place to change colors
  • consistent look across all screens
  • easier to read code (THEME["primary"] instead of "#2563eb")
  • prepares your project for proper UI design

Step 4: Create a Styled Button Helper

Tkinter’s default buttons look outdated.

Create a helper that returns a flat, color-coded button:

python
def _styled_button(parent, text, command, kind="primary"):
    colors = {
        "primary": (THEME["primary"], "white"),
        "success": (THEME["success"], "white"),
        "danger":  (THEME["danger"],  "white"),
        "ghost":   (THEME["card"],    THEME["text"]),
    }
    bg, fg = colors[kind]

    return tk.Button(
        parent, text=text, command=command,
        bg=bg, fg=fg, activebackground=bg, activeforeground=fg,
        font=FONT_BTN, relief="flat", bd=0, padx=14, pady=6,
        cursor="hand2",
    )

Now any screen can call _styled_button(parent, "Login", handle_login, "primary") and get a consistent look.


Step 5: Create Main Window

python
def create_app():
    window = tk.Tk()
    window.title("Productivity App")
    window.geometry("900x620")
    window.minsize(820, 560)
    window.configure(bg=THEME["bg"])
    return window

The window is wider than before because the dashboard will use a two-column layout in the next lesson.


Step 6: Helper to Clear the Window

When switching between screens (login → dashboard → login), you need to remove the old widgets first.

python
def _clear(window):
    for child in window.winfo_children():
        child.destroy()

Step 7: Build the Login Screen

The login screen will be a centered card with:

  • a title
  • a subtitle
  • username and password fields
  • a message label (for errors / confirmations)
  • Login and Create Account buttons
python
def show_login(window):
    _clear(window)

    # Outer container fills the window so we can center the card inside it.
    outer = tk.Frame(window, bg=THEME["bg"])
    outer.pack(fill="both", expand=True)

    # The card itself — fixed size, centered with .place().
    card = tk.Frame(
        outer, bg=THEME["card"],
        highlightbackground=THEME["border"], highlightthickness=1,
    )
    card.place(relx=0.5, rely=0.5, anchor="center", width=380, height=420)

    # Title and subtitle
    tk.Label(
        card, text="Productivity App", font=FONT_TITLE,
        bg=THEME["card"], fg=THEME["text"],
    ).pack(pady=(30, 4))

    tk.Label(
        card, text="Sign in to continue", font=FONT_LABEL,
        bg=THEME["card"], fg=THEME["muted"],
    ).pack(pady=(0, 20))

    # Username field
    tk.Label(card, text="Username", font=FONT_LABEL,
             bg=THEME["card"], fg=THEME["muted"]).pack(anchor="w", padx=40)
    username_entry = tk.Entry(
        card, font=FONT_LABEL, relief="flat",
        bg="#f9fafb", highlightthickness=1,
        highlightbackground=THEME["border"],
    )
    username_entry.pack(fill="x", padx=40, ipady=6, pady=(2, 12))

    # Password field
    tk.Label(card, text="Password", font=FONT_LABEL,
             bg=THEME["card"], fg=THEME["muted"]).pack(anchor="w", padx=40)
    password_entry = tk.Entry(
        card, show="•", font=FONT_LABEL, relief="flat",
        bg="#f9fafb", highlightthickness=1,
        highlightbackground=THEME["border"],
    )
    password_entry.pack(fill="x", padx=40, ipady=6, pady=(2, 8))

    # Message label (filled in later when login is wired up)
    message_label = tk.Label(card, text="", font=FONT_LABEL,
                             bg=THEME["card"], fg=THEME["danger"])
    message_label.pack(pady=(4, 6))

    # Buttons
    _styled_button(card, "Login", lambda: None, "primary").pack(
        fill="x", padx=40, pady=(8, 6), ipady=4)
    _styled_button(card, "Create account", lambda: None, "success").pack(
        fill="x", padx=40, pady=(0, 20), ipady=4)

    return card, username_entry, password_entry

The buttons use lambda: None for now. In the next lesson you will replace these with real login and registration handlers.


Why .place() for the Card?

  • pack() and grid() align widgets top-to-bottom or in rows/columns.
  • .place() lets you position something at exact coordinates.
  • relx=0.5, rely=0.5, anchor="center" puts the card’s center at the window’s center.

This is the standard way to center a “card” in Tkinter.


Step 8: Update main.py

python
from app.services.database import create_tables
from app.ui.app_ui import create_app, show_login

def main():
    create_tables()

    window = create_app()
    show_login(window)

    window.mainloop()

if __name__ == "__main__":
    main()

Result

When you run the program, you should see:

  • a window with a light grey background
  • a white centered card
  • “Productivity App” title
  • “Sign in to continue” subtitle
  • username and password fields with bullet character masking
  • a blue Login button and a green Create Account button

Why This Step Matters

You are separating:

  • backend logic → services
  • frontend UI → ui

You are also setting up:

  • a reusable theme
  • helper functions
  • a structure that will scale to the dashboard

This is how real applications are organized.


Important Notes

  • Do not mix logic into UI yet
  • Keep the theme dictionary at the top of the file
  • Use _styled_button everywhere instead of raw tk.Button
  • Each screen should be its own function
  • Always call _clear(window) at the start of a screen function

Current Project Structure

text
app/
    services/
        database.py
        user_service.py
        task_service.py
        expense_service.py
        dashboard_service.py
    ui/
        app_ui.py

Summary

You created the base GUI structure with a theme, a styled button helper, and a polished centered login card.

In the next lesson you will build the dashboard layout — a header bar, colored stat cards, and side-by-side panels for tasks and expenses.