Chuyển tới nội dung chính

Bài 2: Widget Cơ Bản

Giai đoạn 1 – Nhập Môn · Mục tiêu: Thành thạo các widget cơ bản — Label, Button, Entry, Text, Frame — và biết cách cấu hình từng loại.


1. Widget là gì?

Widget là các thành phần giao diện (controls) trong Tkinter: nút bấm, ô nhập liệu, nhãn văn bản, v.v.

WidgetMô tảDùng khi nào
LabelHiển thị văn bản / hình ảnhTiêu đề, nhãn, thông báo
ButtonNút bấm kích hoạt hành độngClick để thực hiện lệnh
EntryÔ nhập 1 dòng văn bảnTên, email, mật khẩu
TextVùng nhập nhiều dòngGhi chú, nội dung dài
FrameKhung chứa widget khácNhóm các widget lại

2. Label — Nhãn văn bản

2.1. Label cơ bản

import tkinter as tk

root = tk.Tk()
root.title("Label Demo")
root.geometry("400x300")

# Label đơn giản
lbl = tk.Label(root, text="Xin chào!")
lbl.pack()

root.mainloop()

2.2. Tùy chỉnh Label

import tkinter as tk

root = tk.Tk()
root.geometry("400x350")

# Label với nhiều tùy chỉnh
lbl = tk.Label(
root,
text="Tiêu đề chính",
font=("Arial", 20, "bold"),
fg="#2C3E50", # Màu chữ
bg="#ECF0F1", # Màu nền
width=20, # Chiều rộng (tính theo ký tự)
height=2, # Chiều cao (tính theo dòng)
relief="groove", # Kiểu viền: flat, raised, sunken, groove, ridge
padx=10, # Padding ngang bên trong
pady=10, # Padding dọc bên trong
anchor="center" # Căn chỉnh: n, s, e, w, center, nw, ne, sw, se
)
lbl.pack(pady=20)

root.mainloop()

2.3. Cập nhật Label động

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

count = 0
lbl = tk.Label(root, text="0", font=("Arial", 30))
lbl.pack(pady=20)

def tang():
global count
count += 1
lbl.config(text=str(count)) # Cập nhật nội dung

tk.Button(root, text="Tăng", command=tang).pack()
root.mainloop()

:::tip StringVar — Cách khuyến nghị Thay vì dùng label.config(text=...), nên dùng StringVar để liên kết dữ liệu với widget:

var = tk.StringVar(value="0")
label = tk.Label(root, textvariable=var)
var.set("Giá trị mới") # Label tự động cập nhật

:::


3. Button — Nút bấm

3.1. Button cơ bản

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

def say_hello():
print("Xin chào! ")

# Cách 1: command truyền tên hàm
btn1 = tk.Button(root, text="In ra console", command=say_hello)
btn1.pack(pady=10)

# Cách 2: lambda cho lệnh ngắn
btn2 = tk.Button(root, text="Thoát", command=lambda: root.destroy())
btn2.pack(pady=10)

root.mainloop()

3.2. Bật/tắt Button

import tkinter as tk

root = tk.Tk()
root.geometry("300x200")

def toggle():
if btn_action["state"] == "normal":
btn_action.config(state="disabled")
btn_toggle.config(text="Bật lại")
else:
btn_action.config(state="normal")
btn_toggle.config(text="Tắt đi")

btn_action = tk.Button(root, text="Hành động", command=lambda: print("Click!"))
btn_action.pack(pady=10)

btn_toggle = tk.Button(root, text="Tắt đi", command=toggle)
btn_toggle.pack(pady=10)

root.mainloop()

3.3. Button style đẹp

import tkinter as tk

root = tk.Tk()
root.geometry("350x250")
root.configure(bg="#1A1A2E")

styles = {
"primary": {"bg": "#3498DB", "activebackground": "#2980B9"},
"success": {"bg": "#27AE60", "activebackground": "#229954"},
"danger": {"bg": "#E74C3C", "activebackground": "#CB4335"},
}

for name, style in styles.items():
btn = tk.Button(
root,
text=name.capitalize(),
font=("Arial", 11, "bold"),
fg="white",
activeforeground="white",
relief="flat",
padx=20, pady=8,
cursor="hand2",
**style
)
btn.pack(pady=8)

root.mainloop()

4. Entry — Ô nhập liệu 1 dòng

4.1. Entry cơ bản

import tkinter as tk

root = tk.Tk()
root.geometry("350x200")

tk.Label(root, text="Nhập tên:").pack(pady=5)

entry = tk.Entry(root, width=30, font=("Arial", 12))
entry.pack(pady=5)

def show_name():
name = entry.get() # Lấy nội dung
print(f"Tên: {name}")

tk.Button(root, text="Xác nhận", command=show_name).pack(pady=10)
root.mainloop()

4.2. Ô mật khẩu

import tkinter as tk

root = tk.Tk()
root.geometry("350x200")

tk.Label(root, text="Mật khẩu:").pack(pady=5)

# show="*" ẩn ký tự nhập
entry_pass = tk.Entry(root, show="*", width=25, font=("Arial", 12))
entry_pass.pack(pady=5)

def show_pass():
print(entry_pass.get())

tk.Button(root, text="Xem mật khẩu", command=show_pass).pack(pady=10)
root.mainloop()

4.3. Các thao tác với Entry

import tkinter as tk

root = tk.Tk()
root.geometry("350x250")

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

# Đặt nội dung ban đầu
entry.insert(0, "Nội dung mặc định")

def clear():
entry.delete(0, tk.END) # Xóa toàn bộ

def get_selection():
try:
print(entry.selection_get()) # Lấy văn bản đang chọn
except:
print("Không có gì được chọn")

tk.Button(root, text="Xóa", command=clear).pack(pady=5)
tk.Button(root, text="Lấy vùng chọn", command=get_selection).pack(pady=5)

root.mainloop()

5. Text — Vùng nhập nhiều dòng

5.1. Text cơ bản

import tkinter as tk

root = tk.Tk()
root.geometry("400x350")

tk.Label(root, text="Ghi chú:", font=("Arial", 11)).pack(anchor="w", padx=10)

text_area = tk.Text(
root,
width=45,
height=10,
font=("Arial", 11),
wrap="word", # Xuống dòng theo từ (word/char/none)
padx=5, pady=5
)
text_area.pack(padx=10, pady=5)

def get_text():
content = text_area.get("1.0", tk.END) # "dòng.cột"
print(repr(content))

tk.Button(root, text="Lấy nội dung", command=get_text).pack(pady=5)
root.mainloop()

5.2. Thêm Scrollbar cho Text

import tkinter as tk

root = tk.Tk()
root.geometry("400x350")

frame = tk.Frame(root)
frame.pack(fill="both", expand=True, padx=10, pady=10)

scrollbar = tk.Scrollbar(frame)
scrollbar.pack(side="right", fill="y")

text_area = tk.Text(
frame,
yscrollcommand=scrollbar.set,
font=("Consolas", 11)
)
text_area.pack(side="left", fill="both", expand=True)

scrollbar.config(command=text_area.yview)

# Thêm nhiều dòng để test scroll
for i in range(50):
text_area.insert(tk.END, f"Dòng {i+1}: Hello Tkinter!\n")

root.mainloop()

5.3. Thao tác với Text

import tkinter as tk

root = tk.Tk()
root.geometry("400x300")

text = tk.Text(root, font=("Arial", 11))
text.pack(fill="both", expand=True, padx=10, pady=10)

def insert_text():
text.insert(tk.END, "Nội dung thêm vào\n") # Chèn cuối
text.insert("1.0", ">> Đầu trang\n") # Chèn đầu
text.insert("2.5", "<<giữa>>") # Chèn tại dòng 2, cột 5

def clear_text():
text.delete("1.0", tk.END) # Xóa toàn bộ

def get_all():
print(text.get("1.0", tk.END))

frame = tk.Frame(root)
frame.pack()
tk.Button(frame, text="Thêm", command=insert_text).pack(side="left", padx=5)
tk.Button(frame, text="Xóa", command=clear_text).pack(side="left", padx=5)
tk.Button(frame, text="Lấy", command=get_all).pack(side="left", padx=5)

root.mainloop()

6. Frame — Khung chứa

Frame là widget vô hình dùng để nhómtổ chức các widget khác.

import tkinter as tk

root = tk.Tk()
root.title("Frame Demo")
root.geometry("400x300")

# Frame tiêu đề
header = tk.Frame(root, bg="#2C3E50", height=60)
header.pack(fill="x")
header.pack_propagate(False) # Giữ nguyên kích thước

tk.Label(header, text=" Ứng dụng của tôi",
font=("Arial", 14, "bold"),
fg="white", bg="#2C3E50").pack(side="left", padx=15, pady=15)

# Frame nội dung
content = tk.Frame(root, bg="#ECF0F1")
content.pack(fill="both", expand=True, padx=10, pady=10)

tk.Label(content, text="Nội dung chính ở đây",
bg="#ECF0F1", font=("Arial", 12)).pack(expand=True)

# Frame chân trang
footer = tk.Frame(root, bg="#BDC3C7", height=35)
footer.pack(fill="x", side="bottom")
footer.pack_propagate(False)

tk.Label(footer, text=" 2025 My App",
bg="#BDC3C7", fg="#7F8C8D").pack(pady=7)

root.mainloop()

7. Biến kiểm soát (Control Variables)

Tkinter có các biến đặc biệt để liên kết dữ liệu với widget:

BiếnKiểu dữ liệuDùng với
StringVarstrLabel, Entry, Combobox
IntVarintCheckbutton, Radiobutton, Spinbox
DoubleVarfloatScale, Entry
BooleanVarboolCheckbutton
import tkinter as tk

root = tk.Tk()
root.geometry("350x200")

# StringVar liên kết Entry và Label
var = tk.StringVar(value="Gõ gì đó...")

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

# Label tự động cập nhật khi Entry thay đổi
label = tk.Label(root, textvariable=var, font=("Arial", 14), fg="#2980B9")
label.pack(pady=10)

root.mainloop()

Bài tập thực hành

Trắc nghiệm

  1. Hàm nào lấy nội dung của Entry?

    • A. entry.value()
    • B. entry.read()
    • C. entry.get()
    • D. entry.text()
  2. Tham số nào ẩn ký tự trong Entry (dùng cho mật khẩu)?

    • A. hidden=True
    • B. mask="*"
    • C. show="*"
    • D. password=True
  3. Để xóa toàn bộ nội dung Text widget, dùng lệnh nào?

    • A. text.clear()
    • B. text.delete("1.0", tk.END)
    • C. text.remove(all=True)
    • D. text.erase()

Thực hành

  1. Tạo form "Đăng ký thành viên" gồm: Họ tên (Entry), Email (Entry), Mật khẩu (Entry ẩn), nút "Đăng ký" in thông tin ra console.
  2. Tạo app "Notepad mini": Text với Scrollbar, 3 nút: Xóa, Đếm từ, Đảo ngược văn bản.
  3. Dùng StringVar tạo form có Label tự động hiển thị nội dung đang gõ trong Entry.
  4. (Nâng cao) Tạo app "Bộ chuyển đổi nhiệt độ" (Celsius Fahrenheit) dùng Entry + Label + Button.

Bài trước: Bài 1 – Giới Thiệu Tkinter · Bài tiếp: Bài 3 – Quản Lý Bố Cục