Belajar Python GUI Tkinter: Bikin Aplikasi Desktop Lengkap untuk Pemula 2026

| | Python
Belajar Python GUI Tkinter: Bikin Aplikasi Desktop Lengkap untuk Pemula 2026

Tkinter adalah library GUI bawaan Python. Tanpa pip install apa pun.

jika kalian sudah nyaman dengan Python console dan ingin programnya punya jendela, tombol, dan form yang bisa diklik, maka Tkinter adalah langkah paling natural selanjutnya. salah satu project Tkinter yang paling berkesan bagi saya adalah aplikasi To-Do List kecil yang saya buat untuk menggantikan catatan tempel di meja kerja. ternyata membuat aplikasi desktop dengan Python semudah itu, dan hasilnya benar-benar dipakai setiap hari 🙂. mari kita mulai dari window pertama sampai aplikasi lengkap yang bisa jadi EXE.

kalau kalian sudah paham OOP di Python, maka class TodoApp di bawah akan terasa familiar. dan kalau mau simpan data biar tidak hilang, kalian bisa sambungkan ke file handling atau SQLite nanti.

Daftar Isi

1. Kenapa Tkinter di 2026 Masih Kepakai

jika kalian cari python gui di 2026, maka akan muncul banyak nama seperti PyQt, Kivy, Flet, CustomTkinter, sampai Electron. tapi Tkinter tetap punya tempatnya sendiri:

  • bawaan Python, tidak perlu pip install, jadi tidak ada drama versi
  • ringan, startup cepat, cocok untuk tools internal, form input, atau utilitas kecil
  • stabil, API-nya hampir tidak berubah sejak Python 3.x, tutorial lama masih jalan
  • cukup untuk 90% kebutuhan desktop sederhana, kalau butuh animasi berat atau UI mirip web baru lirik alternatif

di Python 3.12 dan 3.13, Tkinter sudah support DPI scaling lebih baik dan ttk makin matang. kalau mau tampilan lebih modern tanpa pindah framework, kalian bisa pakai ttkbootstrap atau CustomTkinter yang dibangun di atas Tkinter, jadi ilmunya tetap kepakai.

2. Window Pertama

jika sudah siap, maka window pertama cuma butuh 4 baris:

import tkinter as tk

root = tk.Tk()
root.title("Aplikasi Saya")
root.geometry("400x300")  # lebar x tinggi
root.mainloop()  # loop utama, wajib di akhir

Tk() itu jendela utama, title untuk judul di title bar, geometry untuk ukuran awal. mainloop() bikin jendela tetap hidup dan nunggu event klik atau ketik, tanpa itu jendela langsung ketutup.

sedikit sentuhan biar tidak blur di layar 4K Windows:

import tkinter as tk
try:
    import ctypes
    ctypes.windll.shcore.SetProcessDpiAwareness(1)
except:
    pass

root = tk.Tk()
root.title("Aplikasi Saya")
root.geometry("400x300")
# opsional, biar tidak bisa di-resize sembarangan
# root.resizable(False, False)
root.mainloop()

jika kalian jalankan, maka akan muncul jendela kosong ukuran 400x300. dari sini kita tempel widget.

3. Widget Dasar yang Wajib Kenal

jika window adalah kanvas, maka widget adalah isinya. ini yang paling sering saya pakai:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("Widget Dasar")
root.geometry("350x250")

label = tk.Label(root, text="Halo Dunia!", font=("Arial", 14))
label.pack(pady=10)

entry = tk.Entry(root, width=30)
entry.pack(pady=5)
entry.insert(0, "ketik di sini")
entry.focus()  # langsung fokus biar bisa ketik

button = tk.Button(root, text="Klik Saya", command=lambda: print(f"isi: {entry.get()}"))
button.pack(pady=10)

# widget lain yang sering kepakai
var = tk.BooleanVar()
check = tk.Checkbutton(root, text="Saya setuju", variable=var)
check.pack()

text = tk.Text(root, height=4, width=30)
text.pack(pady=5)
text.insert("1.0", "Text area untuk catatan panjang...")

root.mainloop()

catatan kecil yang sering kelupaan:

  • Entry untuk satu baris, Text untuk banyak baris. Text pakai index "1.0" (baris 1 kolom 0) bukan 0.
  • command= di Button jangan pakai kurung, command=fungsi bukan command=fungsi(). kalau butuh parameter, bungkus pakai lambda.
  • entry.get() untuk ambil teks, entry.delete(0, tk.END) untuk hapus, entry.insert(0, "isi") untuk isi awal.

widget lain yang bakal ketemu di project nyata:

from tkinter import ttk

# Combobox (dropdown)
combo = ttk.Combobox(root, values=["Pilih", "Python", "MySQL", "Tkinter"])
combo.current(0)
combo.pack(pady=5)

# Spinbox
spin = tk.Spinbox(root, from_=1, to=10)
spin.pack(pady=5)

# Listbox sudah ada di studi kasus bawah

4. Layout Manager: pack, grid, place

jika widget sudah ada, maka selanjutnya atur posisinya. Tkinter punya tiga cara, jangan dicampur dalam satu parent yang sama:

# pack() - sederhana, vertikal atau horizontal
# cocok untuk layout atas-bawah
label.pack(pady=5)
entry.pack(pady=5)
button.pack(pady=5)

# grid() - baris dan kolom seperti Excel, paling rapi untuk form
# cocok untuk form label-entry sejajar
tk.Label(root, text="Nama:").grid(row=0, column=0, sticky="e", padx=5, pady=5)
tk.Entry(root).grid(row=0, column=1, padx=5, pady=5)
tk.Label(root, text="Email:").grid(row=1, column=0, sticky="e", padx=5, pady=5)
tk.Entry(root).grid(row=1, column=1, padx=5, pady=5)

# place() - koordinat absolut x,y
# jarang dipakai, hanya untuk posisi presisi
tk.Button(root, text="Pojok").place(x=10, y=10)

aturan praktis saya:

  • untuk jendela sederhana, pakai pack() saja, cepat jadi
  • untuk form, pakai grid() biar label dan entry sejajar rapi, jangan lupa sticky="w" atau "e" biar tidak tengah terus
  • untuk grid(), atur root.columnconfigure(1, weight=1) biar kolom entry melebar saat window di-resize
  • jangan pakai pack() dan grid() barengan di frame yang sama, nanti error cannot use geometry manager. beda frame boleh.

contoh grid yang rapi:

import tkinter as tk

root = tk.Tk()
root.title("Form")
root.geometry("300x120")
root.columnconfigure(1, weight=1)

tk.Label(root, text="Nama:").grid(row=0, column=0, sticky="e", padx=5, pady=5)
e1 = tk.Entry(root)
e1.grid(row=0, column=1, sticky="ew", padx=5, pady=5)

tk.Label(root, text="Kota:").grid(row=1, column=0, sticky="e", padx=5, pady=5)
e2 = tk.Entry(root)
e2.grid(row=1, column=1, sticky="ew", padx=5, pady=5)

tk.Button(root, text="Simpan").grid(row=2, column=1, sticky="e", padx=5, pady=10)

root.mainloop()

5. Event Handling dan StringVar

jika tombol sudah bisa diklik, maka selanjutnya tangani event lain seperti Enter atau perubahan teks:

import tkinter as tk

root = tk.Tk()
root.title("Event")

entry = tk.Entry(root, width=30)
entry.pack(pady=10)

label = tk.Label(root, text="ketik lalu tekan Enter")
label.pack()

def on_enter(event):
    label.config(text=f"kalian ketik: {entry.get()}")
    entry.delete(0, tk.END)

# bind Enter ke entry
entry.bind("<Return>", on_enter)

# StringVar untuk data yang auto update
nama_var = tk.StringVar(value="Budi")
tk.Label(root, textvariable=nama_var).pack(pady=5)

def ganti():
    nama_var.set("Sudah diganti!")

tk.Button(root, text="Ganti Nama", command=ganti).pack(pady=5)

root.mainloop()

command= hanya untuk klik Button dan Checkbutton. untuk keyboard, mouse, atau event lain, pakai bind("<Event>", fungsi). event yang sering dipakai: "<Return>" untuk Enter, "<Key>" untuk tiap ketik, "<Button-1>" untuk klik kiri.

StringVar, IntVar, BooleanVar itu variabel khusus Tkinter yang kalau nilainya diubah, widget yang pakai textvariable= otomatis keupdate. enak untuk form yang saling terhubung.

6. Ttk Biar Tidak Kelihatan Jadul

jika kalian merasa widget tk.Button kelihatan kotak jadul, maka ganti ke ttk:

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
root.title("Modern dengan ttk")
root.geometry("350x200")

style = ttk.Style()
# coba tema: 'clam', 'alt', 'default', 'classic'
try:
    style.theme_use("clam")
except:
    pass
style.configure("TButton", font=("Segoe UI", 10), padding=6)
style.configure("TLabel", font=("Segoe UI", 10))

ttk.Label(root, text="Nama:").pack(pady=5)
ttk.Entry(root, width=30).pack(pady=5)
ttk.Button(root, text="Simpan").pack(pady=10)

# kalau mau lebih modern lagi tanpa ganti framework, di 2026 banyak yang pakai ttkbootstrap
# pip install ttkbootstrap
# import ttkbootstrap as ttk
# root = ttk.Window(themename="flatly")

root.mainloop()

ttk ikut tema OS, jadi di Windows 11 tampilannya lebih halus daripada tk biasa. untuk project yang butuh dark mode cepat, ttkbootstrap atau CustomTkinter adalah upgrade paling gampang, API-nya tetap mirip Tkinter jadi tidak perlu belajar ulang.

7. Studi Kasus: To-Do List dengan Simpan File

jika semua konsep di atas digabung, maka jadinya To-Do List yang tidak cuma di memori, tapi kesimpan ke file biar tidak hilang saat ditutup. ini versi yang sudah saya pakai sehari-hari, ada simpan ke todo.json:

import tkinter as tk
from tkinter import messagebox
import json
from pathlib import Path

FILE = Path("todo.json")

class TodoApp:
    def __init__(self, root):
        self.root = root
        root.title("To-Do List")
        root.geometry("380x480")

        # load data kalau ada
        self.tasks = self.load_tasks()

        # Input
        top = tk.Frame(root)
        top.pack(pady=10, padx=10, fill="x")

        self.entry = tk.Entry(top, width=28)
        self.entry.pack(side=tk.LEFT, padx=(0, 5))
        self.entry.bind("<Return>", lambda e: self.add_task())
        self.entry.focus()

        tk.Button(top, text="Tambah", command=self.add_task).pack(side=tk.LEFT)

        # Listbox + scrollbar
        mid = tk.Frame(root)
        mid.pack(pady=5, padx=10, fill="both", expand=True)

        self.listbox = tk.Listbox(mid, width=40, height=15)
        self.listbox.pack(side=tk.LEFT, fill="both", expand=True)

        sb = tk.Scrollbar(mid, command=self.listbox.yview)
        sb.pack(side=tk.RIGHT, fill="y")
        self.listbox.config(yscrollcommand=sb.set)

        # isi listbox
        for t in self.tasks:
            self.listbox.insert(tk.END, t)

        # Buttons bawah
        btn_frame = tk.Frame(root)
        btn_frame.pack(pady=10)

        tk.Button(btn_frame, text="Hapus", command=self.delete_task).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="Clear", command=self.clear_tasks).pack(side=tk.LEFT, padx=5)
        tk.Button(btn_frame, text="Simpan", command=self.save_tasks).pack(side=tk.LEFT, padx=5)

        # auto save saat close
        root.protocol("WM_DELETE_WINDOW", self.on_close)

    def load_tasks(self):
        if FILE.exists():
            try:
                return json.loads(FILE.read_text(encoding="utf-8"))
            except:
                return []
        return []

    def save_tasks(self):
        FILE.write_text(json.dumps(self.tasks, ensure_ascii=False, indent=2), encoding="utf-8")
        messagebox.showinfo("Sukses", "Tersimpan ke todo.json")

    def on_close(self):
        FILE.write_text(json.dumps(self.tasks, ensure_ascii=False, indent=2), encoding="utf-8")
        self.root.destroy()

    def add_task(self):
        task = self.entry.get().strip()
        if task:
            self.tasks.append(task)
            self.listbox.insert(tk.END, task)
            self.entry.delete(0, tk.END)
        else:
            messagebox.showwarning("Peringatan", "Task tidak boleh kosong!")

    def delete_task(self):
        sel = self.listbox.curselection()
        if not sel:
            messagebox.showwarning("Peringatan", "Pilih task yang akan dihapus!")
            return
        idx = sel[0]
        self.listbox.delete(idx)
        del self.tasks[idx]

    def clear_tasks(self):
        if messagebox.askyesno("Konfirmasi", "Hapus semua task?"):
            self.listbox.delete(0, tk.END)
            self.tasks.clear()

if __name__ == "__main__":
    root = tk.Tk()
    app = TodoApp(root)
    root.mainloop()

jika kalian mau upgrade lagi, maka ganti json ke SQLite biar bisa search dan filter, atau tambah try-except seperti di error handling biar load_tasks tidak crash kalau file rusak.

8. Build Jadi EXE

jika aplikasi sudah jadi di laptop kalian, maka langkah selanjutnya adalah bikin file EXE biar bisa jalan di komputer lain tanpa install Python:

pip install pyinstaller

# build satu file, tanpa console hitam di belakang
pyinstaller --onefile --windowed --name TodoApp todo.py

# hasil di folder dist/TodoApp.exe
# --onefile = satu file exe
# --windowed = tanpa jendela console (untuk GUI)
# --name = nama exe

catatan 2026 untuk PyInstaller 6.x:

  • pertama kali build agak lama karena analisis dependency, tunggu sampai completed successfully
  • kalau pakai ttkbootstrap atau Pillow, tambah --collect-all ttkbootstrap kalau icon tidak kebawa
  • untuk mengurangi false positive antivirus, jangan pakai --onefile yang di-compress berlebihan, dan sign exe kalau untuk distribusi
  • alternatif modern kalau mau installer proper adalah briefcase atau flet pack, tapi untuk tools internal, PyInstaller sudah cukup

jika exe sudah jadi, maka cukup kirim file dist/TodoApp.exe beserta todo.json kalau ada, tidak perlu kirim folder build atau __pycache__.

Kesimpulan

  • Tkinter itu bawaan Python, jadi tidak perlu install, cocok untuk GUI desktop ringan di 2026
  • window dibuat dari Tk(), atur title dan geometry, tutup dengan mainloop()
  • widget utama: Label, Entry, Button, Text, Listbox, Frame, plus ttk untuk versi modern
  • layout: pack() untuk susun simpel, grid() untuk form tabel, place() untuk absolut, jangan campur dalam satu parent
  • event: command= untuk klik, bind("<Return>", ...) untuk keyboard, StringVar untuk data reaktif
  • biar modern: pakai ttk atau ttkbootstrap/CustomTkinter di atas Tkinter
  • biar awet: simpan ke json atau SQLite, dan build ke EXE pakai pyinstaller --onefile --windowed

habis ini kalian bisa kembangkan To-Do List di atas dengan simpan ke SQLite atau bikin form yang lebih kompleks dengan grid(). kalau butuh validasi input, kombinasikan dengan try except biar error tidak bikin aplikasi crash.

Baca Juga Mengenai :

Pertanyaan yang Sering Diajukan

Apa itu Tkinter di Python?

Tkinter adalah library GUI bawaan Python untuk bikin aplikasi desktop. tidak perlu pip install, cukup import tkinter. cocok untuk tools internal, form input, dan aplikasi ringan.

Apa beda pack, grid, dan place di Tkinter?

pack itu susun vertikal atau horizontal otomatis, paling simpel. grid itu baris dan kolom seperti tabel, paling rapi untuk form. place itu koordinat absolut x y, jarang dipakai kecuali untuk posisi presisi.

Bisa bikin aplikasi Tkinter jadi file EXE?

bisa, pakai PyInstaller dengan perintah pyinstaller --onefile --windowed app.py. hasilnya di folder dist, bisa jalan di Windows tanpa install Python.

Tkinter masih relevan di 2026?

masih, karena bawaan Python dan ringan. untuk aplikasi internal dan tools kecil, Tkinter paling cepat jadi. kalau butuh UI modern mirip web, baru lirik CustomTkinter, ttkbootstrap, atau Flet.

Bagaimana handle klik tombol di Tkinter?

pakai parameter command di Button untuk klik, atau bind seperti entry.bind("<Return>", fungsi) untuk event keyboard. untuk data dinamis pakai StringVar dan trace.

Kenapa window Tkinter blur di layar 4K?

karena DPI scaling Windows. di Python 3.10 ke atas aktifkan dengan ctypes.windll.shcore.SetProcessDpiAwareness(1) sebelum Tk(), atau atur scaling lewat root.tk.call.

Apa itu ttk di Tkinter?

ttk adalah themed widget yang lebih modern dari widget biasa. pakai from tkinter import ttk, lalu ttk.Button, ttk.Entry. tampilannya ikut tema OS dan bisa diganti dengan ttk.Style.

Sigit Nurhanafi avatar
Full-stack developer & technical writer. Berpengalaman di PHP, Laravel, NodeJS, MySQL, dan Python. Aktif menulis tutorial pemrograman dan maintaining open-source projects di PemburuKode sejak 2021.