- vừa được xem lúc

Làm chủ Tkinter từ A đến Z (Phần 3)

0 0 2

Người đăng: Việt Hưng Hoàng

Theo Viblo Asia

Ở bài trước, mình đã chia sẻ với anh em cách hiển thị widget Label bằng pack() . Nó chỉ đơn giản là ném widget vào cửa sổ. Nhưng để xây dựng một ứng dụng thực sự, ta cần kiểm soát vị trí của từng widget một cách chính xác. Trong Tkinter, nhóm các công cụ làm việc này được gọi là Trình quản lý Bố cục (Geometry Managers) bao gồm 3 thành phần chính:

  1. pack(): Xếp chồng các widget lên nhau (theo chiều dọc hoặc ngang).
  2. grid(): Sắp xếp các widget vào một hệ thống lưới (hàng và cột).
  3. place(): Đặt các widget tại một tọa độ (x, y) cụ thể.

pack()

Khi "pack" một widget, nó sẽ chiếm một khoảng không gian và widget tiếp theo sẽ được xếp vào không gian còn lại.

import tkinter as tk root = tk.Tk()
root.title("Tìm hiểu Pack")
root.geometry("300x200") # Mặc định, pack() sẽ xếp các widget từ trên xuống dưới
label1 = tk.Label(root, text="Label 1", bg="red", fg="white")
label1.pack() label2 = tk.Label(root, text="Label 2", bg="green", fg="white")
label2.pack() label3 = tk.Label(root, text="Label 3", bg="blue", fg="white")
label3.pack() root.mainloop()

Lưu ý: bg là background color, fg là foreground color (màu chữ).

Trên dây là một ví dụ đơn giản về pack(). Ngoài ra, pack() cũng cung cấp một số tham số giúp anh em cấu hình linh hoạt hơn:

  • side: Xác định hướng xếp. Giá trị có thể là tk.TOP (mặc định), tk.BOTTOM, tk.LEFT, tk.RIGHT.
  • fill: Widget có lấp đầy không gian được cấp hay không. Giá trị có thể là tk.X (lấp đầy theo chiều ngang), tk.Y (lấp đầy theo chiều dọc), tk.BOTH (lấp đầy cả hai).
  • expand: Khi cửa sổ được thay đổi kích thước, widget có "giành" thêm không gian hay không. Giá trị là True hoặc False.
  • padx, pady: Thêm khoảng đệm (padding) bên ngoài widget theo chiều ngang (x) và chiều dọc (y).

Ví dụ 2

import tkinter as tk root = tk.Tk()
root.title("Pack Nâng Cao")
root.geometry("500x300") # Label này sẽ ở trên cùng và lấp đầy theo chiều ngang
label_top = tk.Label(root, text="TOP", bg="red", fg="white")
label_top.pack(side=tk.TOP, fill=tk.X) # Label này sẽ ở dưới cùng và lấp đầy theo chiều ngang
label_bottom = tk.Label(root, text="BOTTOM", bg="blue", fg="white")
label_bottom.pack(side=tk.BOTTOM, fill=tk.X) # Label này sẽ ở bên trái
label_left = tk.Label(root, text="LEFT", bg="green", fg="white")
label_left.pack(side=tk.LEFT, fill=tk.Y) # Label này sẽ ở bên phải và được "giãn ra" khi cửa sổ thay đổi kích thước
label_right = tk.Label(root, text="RIGHT (expand=True)", bg="purple", fg="white")
# expand=True và fill=tk.BOTH làm cho nó chiếm hết không gian còn lại
label_right.pack(side=tk.RIGHT, expand=True, fill=tk.BOTH, padx=10, pady=10) root.mainloop()

Thông thường mình sẽ dùng pack() khi chỉ cần xây dựng bố cục đơn giản, ví dụ như xếp một vài widget chồng lên nhau, hoặc tạo một thanh công cụ ở trên cùng, một thanh trạng thái ở dưới cùng.


grid()

grid() là công cụ được khuyến khích sử dụng nhiều nhất. Nó chia cửa sổ thành một lưới các hàng (rows) và cột (columns), giống như một bảng tính Excel. Khi thêm widget, anh em cần phải chỉ cần chỉ định widget sẽ nằm ở hàng nào, cột nào.

Ví dụ tạo một form đăng nhập đơn giản

import tkinter as tk root = tk.Tk()
root.title("Tìm hiểu Grid")
root.geometry("300x150") # Tạo các widget
label_user = tk.Label(root, text="Tên đăng nhập:")
label_pass = tk.Label(root, text="Mật khẩu:")
entry_user = tk.Entry(root)
entry_pass = tk.Entry(root, show="*") # show="*" để che mật khẩu
button_login = tk.Button(root, text="Đăng nhập") # Sắp xếp chúng trên lưới
# Hàng 0
label_user.grid(row=0, column=0, padx=5, pady=5)
entry_user.grid(row=0, column=1, padx=5, pady=5) # Hàng 1
label_pass.grid(row=1, column=0, padx=5, pady=5)
entry_pass.grid(row=1, column=1, padx=5, pady=5) # Hàng 2
button_login.grid(row=2, column=1, padx=5, pady=5) root.mainloop()

Các tham số của grid():

  • columnspan: Widget sẽ chiếm bao nhiêu cột. (Giống như "Merge Cells" trong Excel).
  • rowspan: Widget sẽ chiếm bao nhiêu hàng.
  • sticky: Quan trọng! Nó quyết định widget sẽ "dính" vào cạnh nào của ô lưới. Giá trị là các hướng la bàn: N (bắc), S (nam), E (đông), W (tây). Anh em có thể kết hợp chúng, ví dụ: NW (tây bắc), SE (đông nam).
    • sticky='we': Dính vào cạnh Tây và Đông -> widget sẽ giãn ra theo chiều ngang để lấp đầy ô.
    • sticky='ns': Dính vào cạnh Bắc và Nam -> widget sẽ giãn ra theo chiều dọc.
    • sticky='nsew': Lấp đầy toàn bộ ô lưới. Đây là giá trị sẽ dùng rất thường xuyên.

Ví dụ nâng cao với stickycolumnspan:

import tkinter as tk root = tk.Tk()
root.title("Grid Nâng Cao") # Cấu hình để cột 1 có thể co giãn khi cửa sổ thay đổi kích thước
root.columnconfigure(1, weight=1) label_user = tk.Label(root, text="Tên đăng nhập:")
entry_user = tk.Entry(root)
label_pass = tk.Label(root, text="Mật khẩu:")
entry_pass = tk.Entry(root, show="*")
button_login = tk.Button(root, text="Đăng nhập")
button_cancel = tk.Button(root, text="Hủy bỏ") # Dùng sticky='w' (West) để căn lề trái các Label
label_user.grid(row=0, column=0, padx=5, pady=5, sticky='w')
# Dùng sticky='we' (West-East) để ô nhập liệu giãn theo chiều ngang
entry_user.grid(row=0, column=1, columnspan=2, padx=5, pady=5, sticky='we') label_pass.grid(row=1, column=0, padx=5, pady=5, sticky='w')
entry_pass.grid(row=1, column=1, columnspan=2, padx=5, pady=5, sticky='we') # Đặt 2 button trên cùng một hàng
button_login.grid(row=2, column=1, padx=5, pady=5, sticky='e')
button_cancel.grid(row=2, column=2, padx=5, pady=5, sticky='w') root.mainloop()

place()

place() cho phép anh em đặt widget tại một tọa độ cụ thể.

  • x, y: Tọa độ tuyệt đối tính bằng pixel so với góc trên bên trái của cửa sổ cha.
  • relx, rely: Tọa độ tương đối (giá trị từ 0.0 đến 1.0). Ví dụ relx=0.5 có nghĩa là đặt widget ở vị trí giữa theo chiều ngang.

Tuy nhiên rất hiếm khi sử dụng place(). Việc dùng tọa độ tuyệt đối làm cho giao diện:

  • Không co giãn tốt khi thay đổi kích thước cửa sổ.
  • Trông khác nhau trên các hệ điều hành/độ phân giải màn hình khác nhau.
  • Khó bảo trì khi cần thêm/bớt widget.

Nó chỉ hữu ích trong một số trường hợp đặc biệt, ví dụ như đặt một nút bấm lên trên một tấm ảnh.

QUY TẮC VÀNG

KHÔNG BAO GIỜ TRỘN LẪN pack()grid() TRONG CÙNG MỘT CỬA SỔ CHA (master window/frame).

Hai trình quản lý này sử dụng hai thuật toán khác nhau để tính toán không gian. Việc trộn lẫn chúng sẽ làm Tkinter bị bối rối và ứng dụng của anh em có thể sẽ bị treo. Anh em có thể dùng pack() trong một Framegrid() trong một Frame khác, nhưng không được dùng cả hai trực tiếp trong root. (Khái niệm Frame mình sẽ trình bày chi tiét sau, tạm thời anh em có thể hiểu đơn giản đó là các cửa sổ con của root)

Trong bài tiếp theo, mình sẽ cùng anh em tìm hiểu các Widget cơ bản trong Tkinter. Có thắc mắc / góp ý gì anh em cứ để lại comment, mình sẽ phản hồi và tiếp thu nhé 😄.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Lập Trình Hướng Đối Tượng trong Python

Chào các bạn Trong bài này, bạn sẽ tìm hiểu về Lập trình hướng đối tượng (OOP) bằng Python và khái niệm cơ bản của nó và một số các ví dụ. Các bạn cùng tìm hiểu trong bài viết của mình nhé.

0 0 60

- vừa được xem lúc

Lớp trong Python

. Hôm ni, mình học tiếp về bạn “Lớp(class) trong python”, bài blog tiếp theo nằm trong series “Khám phá Đại Bản Doanh Python”(nội dung trong bài series này từ chủ yếu mình lấy từ python.org rồi viết lại hoặc dịch lại theo ngôn ngữ của mình).

0 0 45

- vừa được xem lúc

Tìm hiểu về thư viện Numpy trong Python(Phần 3)

Trong bài viết trước tôi đã giới thiệu cho bạn về NumPy, tìm hiểu về Mảng trong NumPy. Trong bài viết này chúng ta sẽ tiếp tục tìm hiểu về các kiểu dữ liệu khác trong NumPy.

0 0 150

- vừa được xem lúc

Hướng dẫn cài đặt Anaconda trên Ubuntu

Anaconda là một nền tảng mã nguồn mở về Data Science và Machine Learning trên Python thông dụng nhất hiện nay, Anaconda có vai trò đơn giản hóa việc triển khai và quản lí các gói cài đặt khi làm việc với Python. Anaconda được cài đặt dễ dàng trên 3 nền tảng hệ điều hành thông dụng hiện nay là Ubuntu

0 0 51

- vừa được xem lúc

Tùy chỉnh Exceptions trong Python

Chào các bạn trong bài viết này, mình sẽ giới thiệu với các bạn về cách tùy chỉnh các Exceptions trong Python.Mình sẽ giải thích cho các bạn hiểu và cách xử dụng chúng.

0 0 46

- vừa được xem lúc

Không gian tên(namspace) và phạm vi(scope) trong Python

. Khi mình ngồi học và dịch bài "Class trong Python" cho sê-ri "Khám Phá Đại Bản Doanh Python", mình đã đụng hai bạn này, và các bạn thật là trừu tượng và khó gặm. Thế là mình tìm kiếm và viết bài này để hiểu rõ hơn về hai bạn ấy, hi vọng bạn đọc thêm để hiểu về Python nhé.

0 0 60