GIAO DIỆN ĐỒ HỌA VỚI TKINTER (PHẦN 1)¶
1. Giới thiệu về Tkinter¶
1.1. Tkinter là gì?¶
- Tkinter (Tk interface) là thư viện GUI (Graphical User Interface) có sẵn trong Python
- Cho phép tạo các ứng dụng giao diện đồ họa với cửa sổ, nút bấm, hộp văn bản...
- Đơn giản, dễ học và không cần cài đặt thêm
1.2. Tại sao học Tkinter?¶
- Được tích hợp sẵn trong Python
- Dễ học cho người mới bắt đầu
- Tạo được các ứng dụng desktop đơn giản
- Nền tảng để hiểu các thư viện GUI khác
1.3. Cấu trúc cơ bản của ứng dụng Tkinter¶
import tkinter as tk
# Tạo cửa sổ chính
window = tk.Tk()
window.title("Tiêu đề cửa sổ")
window.geometry("400x300")
# Thêm các widget vào đây
# Chạy vòng lặp chính
window.mainloop()
2. Tạo cửa sổ chính (Window)¶
2.1. Tạo cửa sổ cơ bản¶
import tkinter as tk
# Tạo cửa sổ
window = tk.Tk()
window.title("Cửa sổ đầu tiên của tôi")
window.geometry("500x400") # rộng x cao
window.resizable(True, True) # cho phép thay đổi kích thước
# Hiển thị cửa sổ
window.mainloop()
2.2. Các thuộc tính của cửa sổ¶
import tkinter as tk
window = tk.Tk()
window.title("Ứng dụng quản lý học sinh")
window.geometry("600x500")
window.configure(bg="lightblue") # màu nền
window.resizable(False, False) # không cho thay đổi kích thước
# Đặt vị trí cửa sổ ở giữa màn hình
window.eval('tk::PlaceWindow . center')
window.mainloop()
3. Widget Label - Hiển thị văn bản¶
3.1. Label cơ bản¶
import tkinter as tk
window = tk.Tk()
window.title("Label Demo")
window.geometry("400x200")
# Tạo label
label1 = tk.Label(window, text="Xin chào các bạn!")
label1.pack() # Đặt label vào cửa sổ
label2 = tk.Label(window, text="Đây là bài học về Tkinter",
font=("Arial", 14))
label2.pack()
window.mainloop()
3.2. Label với nhiều thuộc tính¶
import tkinter as tk
window = tk.Tk()
window.title("Label nâng cao")
window.geometry("500x300")
# Label với màu sắc và font
label_title = tk.Label(window,
text="CHƯƠNG TRÌNH QUẢN LÝ ĐIỂM",
font=("Times New Roman", 18, "bold"),
fg="blue", # màu chữ
bg="yellow", # màu nền
padx=20, pady=10) # khoảng cách padding
label_title.pack()
# Label thông tin
label_info = tk.Label(window,
text="Nhập điểm các môn học của bạn:",
font=("Arial", 12),
fg="darkgreen")
label_info.pack(pady=20)
window.mainloop()
4. Widget Button - Nút bấm¶
4.1. Button cơ bản¶
import tkinter as tk
def say_hello():
print("Xin chào!")
window = tk.Tk()
window.title("Button Demo")
window.geometry("300x200")
# Tạo button
button1 = tk.Button(window, text="Click me!", command=say_hello)
button1.pack(pady=20)
window.mainloop()
4.2. Button với nhiều chức năng¶
import tkinter as tk
def chao_buoi_sang():
print("Chào buổi sáng!")
def chao_buoi_chieu():
print("Chào buổi chiều!")
def thoat_chuong_trinh():
print("Tạm biệt!")
window.quit()
window = tk.Tk()
window.title("Các nút chức năng")
window.geometry("300x250")
# Các button khác nhau
btn_sang = tk.Button(window, text="Chào buổi sáng",
command=chao_buoi_sang,
bg="lightblue", font=("Arial", 10))
btn_sang.pack(pady=10)
btn_chieu = tk.Button(window, text="Chào buổi chiều",
command=chao_buoi_chieu,
bg="lightgreen", font=("Arial", 10))
btn_chieu.pack(pady=10)
btn_thoat = tk.Button(window, text="Thoát",
command=thoat_chuong_trinh,
bg="red", fg="white", font=("Arial", 10, "bold"))
btn_thoat.pack(pady=10)
window.mainloop()
5. Widget Entry - Hộp nhập liệu¶
5.1. Entry cơ bản¶
import tkinter as tk
window = tk.Tk()
window.title("Entry Demo")
window.geometry("400x200")
# Label hướng dẫn
label = tk.Label(window, text="Nhập tên của bạn:")
label.pack(pady=10)
# Entry box
entry = tk.Entry(window, font=("Arial", 12))
entry.pack(pady=10)
def lay_ten():
ten = entry.get() # Lấy giá trị từ entry
print(f"Tên bạn là: {ten}")
# Button để lấy dữ liệu
button = tk.Button(window, text="Xác nhận", command=lay_ten)
button.pack(pady=10)
window.mainloop()
5.2. Entry cho form nhập điểm¶
import tkinter as tk
window = tk.Tk()
window.title("Nhập điểm học sinh")
window.geometry("400x300")
# Tiêu đề
title = tk.Label(window, text="NHẬP ĐIỂM HỌC SINH",
font=("Arial", 16, "bold"), fg="blue")
title.pack(pady=10)
# Nhập tên
label_ten = tk.Label(window, text="Tên học sinh:")
label_ten.pack()
entry_ten = tk.Entry(window, font=("Arial", 11))
entry_ten.pack(pady=5)
# Nhập điểm Toán
label_toan = tk.Label(window, text="Điểm Toán:")
label_toan.pack()
entry_toan = tk.Entry(window, font=("Arial", 11))
entry_toan.pack(pady=5)
# Nhập điểm Văn
label_van = tk.Label(window, text="Điểm Văn:")
label_van.pack()
entry_van = tk.Entry(window, font=("Arial", 11))
entry_van.pack(pady=5)
def tinh_diem_tb():
try:
ten = entry_ten.get()
diem_toan = float(entry_toan.get())
diem_van = float(entry_van.get())
diem_tb = (diem_toan + diem_van) / 2
print(f"Học sinh: {ten}")
print(f"Điểm TB: {diem_tb:.1f}")
# Xóa các ô nhập sau khi tính
entry_ten.delete(0, tk.END)
entry_toan.delete(0, tk.END)
entry_van.delete(0, tk.END)
except ValueError:
print("Vui lòng nhập số hợp lệ!")
# Button tính điểm
btn_tinh = tk.Button(window, text="Tính điểm TB",
command=tinh_diem_tb,
bg="green", fg="white", font=("Arial", 12))
btn_tinh.pack(pady=20)
window.mainloop()
6. Layout Managers - Quản lý bố cục¶
6.1. Pack Layout¶
import tkinter as tk
window = tk.Tk()
window.title("Pack Layout")
window.geometry("300x400")
# Các widget xếp theo chiều dọc
label1 = tk.Label(window, text="Label 1", bg="red")
label1.pack(fill=tk.X, padx=10, pady=5)
label2 = tk.Label(window, text="Label 2", bg="green")
label2.pack(fill=tk.X, padx=10, pady=5)
label3 = tk.Label(window, text="Label 3", bg="blue")
label3.pack(fill=tk.X, padx=10, pady=5)
# Các button xếp theo chiều ngang
frame = tk.Frame(window)
frame.pack(pady=20)
btn1 = tk.Button(frame, text="Button 1")
btn1.pack(side=tk.LEFT, padx=5)
btn2 = tk.Button(frame, text="Button 2")
btn2.pack(side=tk.LEFT, padx=5)
btn3 = tk.Button(frame, text="Button 3")
btn3.pack(side=tk.LEFT, padx=5)
window.mainloop()
6.2. Grid Layout¶
import tkinter as tk
window = tk.Tk()
window.title("Grid Layout")
window.geometry("400x300")
# Tạo form bằng grid
tk.Label(window, text="Họ tên:").grid(row=0, column=0, sticky="w", padx=10, pady=5)
tk.Entry(window).grid(row=0, column=1, padx=10, pady=5)
tk.Label(window, text="Tuổi:").grid(row=1, column=0, sticky="w", padx=10, pady=5)
tk.Entry(window).grid(row=1, column=1, padx=10, pady=5)
tk.Label(window, text="Lớp:").grid(row=2, column=0, sticky="w", padx=10, pady=5)
tk.Entry(window).grid(row=2, column=1, padx=10, pady=5)
# Button span nhiều cột
tk.Button(window, text="Xác nhận").grid(row=3, column=0, columnspan=2, pady=20)
window.mainloop()
7. Ví dụ tổng hợp - Ứng dụng đơn giản¶
7.1. Máy tính cơ bản¶
import tkinter as tk
class MayTinhDonGian:
def __init__(self):
self.window = tk.Tk()
self.window.title("Máy tính đơn giản")
self.window.geometry("300x400")
# Tạo giao diện
self.tao_giao_dien()
def tao_giao_dien(self):
# Tiêu đề
title = tk.Label(self.window, text="MÁY TÍNH ĐƠN GIẢN",
font=("Arial", 16, "bold"), fg="blue")
title.pack(pady=10)
# Số thứ nhất
tk.Label(self.window, text="Số thứ nhất:").pack()
self.entry1 = tk.Entry(self.window, font=("Arial", 12))
self.entry1.pack(pady=5)
# Số thứ hai
tk.Label(self.window, text="Số thứ hai:").pack()
self.entry2 = tk.Entry(self.window, font=("Arial", 12))
self.entry2.pack(pady=5)
# Các nút phép tính
frame_buttons = tk.Frame(self.window)
frame_buttons.pack(pady=20)
tk.Button(frame_buttons, text="+", command=self.cong,
width=5, font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
tk.Button(frame_buttons, text="-", command=self.tru,
width=5, font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
tk.Button(frame_buttons, text="×", command=self.nhan,
width=5, font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
tk.Button(frame_buttons, text="÷", command=self.chia,
width=5, font=("Arial", 12)).pack(side=tk.LEFT, padx=5)
# Kết quả
self.label_ketqua = tk.Label(self.window, text="Kết quả: ",
font=("Arial", 14, "bold"), fg="red")
self.label_ketqua.pack(pady=20)
# Nút xóa
tk.Button(self.window, text="Xóa", command=self.xoa,
bg="orange", font=("Arial", 12)).pack(pady=10)
def lay_so(self):
try:
so1 = float(self.entry1.get())
so2 = float(self.entry2.get())
return so1, so2
except ValueError:
self.label_ketqua.config(text="Lỗi: Vui lòng nhập số hợp lệ!")
return None, None
def cong(self):
so1, so2 = self.lay_so()
if so1 is not None:
ketqua = so1 + so2
self.label_ketqua.config(text=f"Kết quả: {ketqua}")
def tru(self):
so1, so2 = self.lay_so()
if so1 is not None:
ketqua = so1 - so2
self.label_ketqua.config(text=f"Kết quả: {ketqua}")
def nhan(self):
so1, so2 = self.lay_so()
if so1 is not None:
ketqua = so1 * so2
self.label_ketqua.config(text=f"Kết quả: {ketqua}")
def chia(self):
so1, so2 = self.lay_so()
if so1 is not None:
if so2 != 0:
ketqua = so1 / so2
self.label_ketqua.config(text=f"Kết quả: {ketqua}")
else:
self.label_ketqua.config(text="Lỗi: Không thể chia cho 0!")
def xoa(self):
self.entry1.delete(0, tk.END)
self.entry2.delete(0, tk.END)
self.label_ketqua.config(text="Kết quả: ")
def chay(self):
self.window.mainloop()
# Chạy ứng dụng
if __name__ == "__main__":
may_tinh = MayTinhDonGian()
may_tinh.chay()
8. Bài tập thực hành tại lớp¶
Bài 1: Cửa sổ chào mừng¶
Tạo một cửa sổ với tiêu đề "Chào mừng", có một label hiển thị "Xin chào [Tên bạn]!" và một button "Thoát" để đóng ứng dụng.
Bài 2: Form nhập thông tin cá nhân¶
Tạo form có các trường: Họ tên, Tuổi, Lớp và một button "Hiển thị" để in thông tin ra console.
Bài 3: Máy tính đơn giản 2 số¶
Tạo giao diện để nhập 2 số và thực hiện phép cộng, in kết quả lên label.
Bài 4: Đổi màu nền¶
Tạo cửa sổ với 3 button: "Đỏ", "Xanh", "Vàng". Khi nhấn button nào thì màu nền cửa sổ đổi thành màu đó.
9. Bài tập về nhà¶
Bài 1: Ứng dụng chuyển đổi nhiệt độ¶
Đề bài: Tạo giao diện để chuyển đổi giữa Celsius và Fahrenheit.
💡 Phân tích đề
Các bước thực hiện:
- Tạo cửa sổ chính với title phù hợp
- Tạo 2 Entry để nhập/hiển thị nhiệt độ
- Tạo 2 Button cho chuyển đổi C->F và F->C
- Viết hàm chuyển đổi: F = C * 9/5 + 32
- Viết hàm chuyển đổi ngược: C = (F - 32) * 5/9
- Xử lý lỗi khi nhập dữ liệu không hợp lệ
- Sử dụng grid() để bố trí giao diện
Input/Output mẫu:
Input C | Output F | Input F | Output C |
---|---|---|---|
0 |
32 |
100 |
37.78 |
100 |
212 |
32 |
0 |
Bài 2: Máy tính BMI¶
Đề bài: Tạo form nhập cân nặng và chiều cao, tính chỉ số BMI và hiển thị đánh giá.
💡 Phân tích đề
Các bước thực hiện:
- Tạo form với Entry cho cân nặng (kg) và chiều cao (m)
- Tạo Button "Tính BMI" để thực hiện tính toán
- Tạo Label để hiển thị kết quả BMI
- Tính BMI theo công thức: BMI = cân nặng / (chiều cao)²
- Đánh giá BMI: <18.5 gầy, 18.5-24.9 bình thường, ≥25 thừa cân
- Hiển thị cả số BMI và đánh giá
- Xử lý lỗi nhập liệu và validation
Input/Output mẫu:
Cân nặng (kg) | Chiều cao (m) | BMI | Đánh giá |
---|---|---|---|
70 |
1.75 |
22.86 |
Bình thường |
50 |
1.60 |
19.53 |
Bình thường |
Bài 3: Trò chơi đoán số¶
Đề bài: Tạo game đoán số từ 1-100 với giao diện Tkinter.
💡 Phân tích đề
Các bước thực hiện:
- Import random để tạo số ngẫu nhiên từ 1-100
- Tạo giao diện với Entry nhập số đoán
- Tạo Button "Đoán" và "Chơi lại"
- Tạo Label hiển thị gợi ý (lớn hơn/nhỏ hơn/đúng)
- Đếm số lần đoán và hiển thị
- Khi đoán đúng, hiển thị chúc mừng + số lần đoán
- Button "Chơi lại" để bắt đầu game mới
Input/Output mẫu:
Số bí mật | Số đoán | Kết quả | Lần đoán |
---|---|---|---|
67 |
50 |
Lớn hơn! |
1 |
67 |
80 |
Nhỏ hơn! |
2 |
67 |
67 |
Chính xác! |
3 |
Bài 4: Quản lý danh sách học sinh đơn giản¶
Đề bài: Tạo form để thêm tên học sinh vào danh sách và hiển thị.
💡 Phân tích đề
Các bước thực hiện:
- Tạo Entry để nhập tên học sinh
- Tạo Button "Thêm" để thêm vào danh sách
- Tạo Listbox hoặc Text để hiển thị danh sách
- Tạo list Python để lưu trữ tên học sinh
- Hàm thêm: lấy tên từ Entry, thêm vào list, cập nhật hiển thị
- Tạo Button "Xóa" để xóa học sinh được chọn
- Validation: không thêm tên trống hoặc trùng lặp
Input/Output mẫu:
Hành động | Input | Danh sách hiện tại |
---|---|---|
Thêm | Nguyễn Văn A |
1. Nguyễn Văn A |
Thêm | Trần Thị B |
1. Nguyễn Văn A, 2. Trần Thị B |
Xóa | Chọn item 1 |
1. Trần Thị B |
10. Ghi chú quan trọng¶
10.1. Lưu ý khi sử dụng Tkinter¶
- Luôn gọi
mainloop()
ở cuối để hiển thị cửa sổ - Sử dụng
try-except
khi xử lý dữ liệu từ Entry pack()
,grid()
vàplace()
không nên trộn lẫn trong cùng container- Sử dụng
StringVar()
,IntVar()
để liên kết dữ liệu với widget
10.2. Các widget cơ bản cần nhớ¶
- Label: Hiển thị văn bản hoặc hình ảnh
- Button: Nút bấm để thực hiện hành động
- Entry: Hộp nhập liệu một dòng
- Frame: Container để nhóm các widget
10.3. Layout managers¶
- pack(): Xếp widget theo chiều dọc hoặc ngang
- grid(): Xếp widget theo dạng bảng
- place(): Đặt widget ở vị trí cụ thể (ít dùng)
10.4. Event và Command¶
command
: Gán hàm cho buttonbind()
: Gán sự kiện cho widget- Hàm xử lý sự kiện không có tham số hoặc có tham số event
10.5. Tips học tập¶
- Bắt đầu với các ví dụ đơn giản
- Thực hành tạo nhiều giao diện khác nhau
- Kết hợp với kiến thức đã học (vòng lặp, điều kiện, hàm)
- Tham khảo tài liệu chính thức của Tkinter