Bạn đã bao giờ thấy xấu hổ vì giao diện app Python của mình chưa?
Mình từng viết một tool nội bộ cho team — chức năng thì ổn, nhưng giao diện trông như phần mềm thời Windows XP. Cửa sổ xám xịt, nút bấm vuông vức, font chữ nhỏ xíu. Đồng nghiệp nhìn vào rồi hỏi: “Anh viết cái này bằng gì vậy, trông giống Notepad quá?”
Đó là lúc mình bắt đầu tìm cách làm cho app Python trông đàng hoàng hơn mà không cần học thêm cả một framework mới.
Vấn đề với Tkinter truyền thống
Tkinter là thư viện GUI đi kèm sẵn với Python — không cần cài thêm, chạy được trên Windows, macOS, Linux. Nhưng nhược điểm lớn nhất là giao diện mặc định trông rất cũ. Widget không có bo góc, không có dark mode, không theo style hiện đại nào cả.
Nhiều người chuyển sang PyQt5 hoặc PySide6 — mạnh hơn nhiều, nhưng đi kèm với đó là cả đống thứ cần học: Qt Designer, signal/slot, và licensing PyQt5 khá đau đầu cho dự án thương mại.
Wxpython thì sao? Cũng tương tự — khó bắt đầu, tài liệu ít, cộng đồng nhỏ hơn đáng kể.
Vậy nếu chỉ cần một tool nội bộ đơn giản mà trông cho ra hồn, có cách nào nhẹ nhàng hơn không?
CustomTkinter — Tkinter nhưng được làm lại cho năm 2024
CustomTkinter là thư viện Python do Tom Schimansky phát triển, về bản chất nó bọc lại Tkinter và thay thế toàn bộ widget bằng phiên bản vẽ lại — bo góc, màu sắc hiện đại, hỗ trợ dark/light mode tự động theo hệ điều hành.
Cái hay nhất: nếu bạn đã biết Tkinter thì gần như không cần học lại gì cả. Cú pháp gần giống hệt, chỉ thêm tiền tố ctk vào tên widget là xong.
Cài đặt
pip install customtkinter
Không có dependency nặng nề. Không cần Qt, không cần compiler C++.
Viết app đầu tiên — từng bước
Lấy ví dụ thực tế: một tool đổi đơn vị nhiệt độ (Celsius ↔ Fahrenheit). Nhỏ thôi, nhưng đủ để thấy CustomTkinter hoạt động thế nào.
Khung cơ bản
import customtkinter as ctk
# Thiết lập giao diện mặc định
ctk.set_appearance_mode("System") # Theo hệ điều hành: Light/Dark
ctk.set_default_color_theme("blue") # Màu chủ đạo: blue, green, dark-blue
app = ctk.CTk() # Cửa sổ chính (thay vì tk.Tk())
app.title("Đổi nhiệt độ")
app.geometry("400x300")
app.mainloop()
Chạy lên là ra ngay một cửa sổ trắng tinh, bo góc, trông như app macOS. Khác biệt rõ ngay từ dòng đầu tiên.
Thêm widget và logic
import customtkinter as ctk
ctk.set_appearance_mode("System")
ctk.set_default_color_theme("blue")
def convert():
try:
celsius = float(entry_celsius.get())
fahrenheit = celsius * 9 / 5 + 32
label_result.configure(text=f"{fahrenheit:.1f} °F")
except ValueError:
label_result.configure(text="Nhập số hợp lệ!")
app = ctk.CTk()
app.title("Đổi nhiệt độ")
app.geometry("400x280")
app.resizable(False, False)
# Tiêu đề
ctk.CTkLabel(app, text="Chuyển đổi nhiệt độ",
font=ctk.CTkFont(size=20, weight="bold")).pack(pady=20)
# Input
entry_celsius = ctk.CTkEntry(app, placeholder_text="Nhập độ C...", width=200)
entry_celsius.pack(pady=10)
# Nút bấm
ctk.CTkButton(app, text="Chuyển sang °F", command=convert, width=200).pack(pady=10)
# Kết quả
label_result = ctk.CTkLabel(app, text="", font=ctk.CTkFont(size=18))
label_result.pack(pady=10)
# Toggle dark/light mode
def toggle_mode():
current = ctk.get_appearance_mode()
ctk.set_appearance_mode("Light" if current == "Dark" else "Dark")
ctk.CTkButton(app, text="Đổi Dark/Light", command=toggle_mode,
fg_color="gray40", hover_color="gray30", width=140).pack(pady=5)
app.mainloop()
Chưa đến 35 dòng code, đã có app trông tử tế với dark mode toggle. Không phải dark mode giả — CustomTkinter vẽ lại widget hoàn toàn, nền tối thật sự.
Các widget hay dùng nhất
CustomTkinter có đủ các widget phổ biến. Đây là những cái mình xài nhiều nhất trong các tool nội bộ:
- CTkEntry — ô nhập liệu, có placeholder text
- CTkButton — nút bấm, tuỳ màu
fg_color,hover_color - CTkLabel — nhãn văn bản, hỗ trợ font tùy chỉnh
- CTkFrame — khung chứa widget, dùng để nhóm layout
- CTkTextbox — text editor nhiều dòng (thay thế
Text) - CTkComboBox — dropdown chọn giá trị
- CTkSwitch — toggle switch kiểu iOS
- CTkProgressBar — thanh tiến trình
- CTkScrollableFrame — frame có scroll, rất tiện khi list dài
- CTkTabview — tab layout, chia màn hình thành nhiều tab
Layout thực tế với nhiều tab
App phức tạp hơn một chút? Mình hay dùng CTkTabview để chia nội dung thay vì nhồi hết vào một màn hình:
import customtkinter as ctk
app = ctk.CTk()
app.geometry("500x350")
app.title("Tool nội bộ")
tabview = ctk.CTkTabview(app, width=480, height=320)
tabview.pack(padx=10, pady=10)
tabview.add("Xử lý file")
tabview.add("Cài đặt")
tabview.add("Log")
# Nội dung tab 1
ctk.CTkLabel(tabview.tab("Xử lý file"),
text="Kéo file vào đây...").pack(pady=40)
# Nội dung tab 3 — textbox để hiển thị log
log_box = ctk.CTkTextbox(tabview.tab("Log"), width=440, height=200)
log_box.pack(padx=10, pady=10)
log_box.insert("end", "[INFO] App khởi động...\n")
app.mainloop()
Một mẹo nhỏ khi viết tool xử lý văn bản
Hồi làm tool xử lý log, mình có phần cần validate regex pattern trước khi đưa vào code Python. Thay vì phải chạy đi chạy lại script, mình hay test nhanh trên toolcraft.app/vi/tools/developer/regex-tester — chạy ngay trên trình duyệt, không cần cài gì, kết quả hiện real-time. Sau khi pattern ổn thì mới paste vào code CustomTkinter. Tiết kiệm khá nhiều thời gian debug.
Đóng gói thành file .exe để chia sẻ
Viết xong app, muốn gửi cho đồng nghiệp dùng mà không cần họ cài Python? Dùng PyInstaller:
# Cài PyInstaller
pip install pyinstaller
# Đóng gói thành 1 file .exe (Windows)
pyinstaller --onefile --windowed --name "TenApp" main.py
# Kết quả nằm trong thư mục dist/
# dist/TenApp.exe
Flag --windowed để ẩn cửa sổ terminal khi chạy (chỉ hiện cửa sổ GUI). --onefile đóng gói tất cả vào 1 file duy nhất, dễ chia sẻ hơn.
Một điều cần biết trước: file exe khi đóng gói với CustomTkinter thường nặng khoảng 30–50MB. Hơi to so với app nhỏ, nhưng với tool nội bộ thì không ai phàn nàn.
CustomTkinter có phù hợp cho dự án lớn không?
Nói thật luôn: không hẳn. Nếu bạn cần app desktop phức tạp — nhiều cửa sổ con, drag-and-drop nâng cao, OpenGL, hay cần build cho mobile — thì PyQt/PySide6 hay Kivy sẽ phù hợp hơn.
Nhưng nếu bạn cần:
- Tool nội bộ cho team (1–10 người dùng)
- Script automation có giao diện thay vì command line
- Prototype nhanh để demo
- App nhỏ nhưng muốn trông đàng hoàng
…thì CustomTkinter là lựa chọn tốt nhất — học nhanh, code ít, kết quả đẹp.
Tóm lại
CustomTkinter lấp đúng cái lỗ hổng mà Tkinter bỏ mặc bao lâu nay: giao diện cũ kỹ. Nó không ôm đồm — chỉ làm tốt một việc duy nhất. Và nếu bạn đã biết Tkinter, gần như không có gì cần học lại.
Lần tới khi cần viết tool nội bộ, thay vì làm command-line script rồi giải thích cách dùng cho cả team, thử bỏ thêm 1–2 tiếng làm giao diện với CustomTkinter — đồng nghiệp sẽ không còn nhìn bạn với ánh mắt nghi ngờ nữa.
