Daily Archives: 01/02/2016

Tkinter – Widget

Trong phần này chúng ta sẽ tìm hiểu về một số widget cơ bản trong Tkinter là Checkbutton, Label, Scale, và Listbox.

Widget là các thành phần cấu tạo nên một ứng dụng GUI. Widget rất đa dạng, có một số widget quan trọng cần phải có của bất kì nền tảng nào kể cả Tkinter ví dụ như button (nút bấm), check box hay scroll bar (thanh cuộn). Ngoài những widget cơ bản lập trình viên còn có thể tùy chỉnh widget của riêng mình.

Checkbutton

Checkbutton là widget hiển thị hộp đánh dấu.

from tkinter import Tk, Frame, Checkbutton
from tkinter import BooleanVar, BOTH

class Example(Frame):
  def __init__(self, parent):
    Frame.__init__(self, parent)
 
    self.parent = parent
    self.initUI()
 
  def initUI(self):
    self.parent.title("Checkbutton")
    self.pack(fill=BOTH, expand=True)
    self.var = BooleanVar()
    
    cb = Checkbutton(self, text="Show Title", variable=self.var, command=self.onClick)
    cb.select()
    cb.place(x=50, y=50)
 
  def onClick(self):
    if self.var.get() == True:
      self.master.title("Checkbutton")
    else:
      self.master.title("")
 
root = Tk()
root.geometry("250x150+300+300")
app = Example(root)
root.mainloop()

Trong ví dụ trên chúng ta hiển thị một check button lên cửa sổ có chức năng hiện/ẩn tiêu đề cửa sổ khi check.

self.var = BooleanVar()

Ở trên chúng ta tạo ra một đối tượng BooleanVar, đối tượng này sẽ được kết nối với checkbutton, mỗi khi trạng thái check thay đổi thì giá trị của self.var cũng sẽ thay đổi.

cb = Checkbutton(self, text="Show title", variable=self.var, command=self.onClick)

Ở dòng trên chúng ta tạo một đối tượng Checkbutton. Chúng ta kết nối biến self.var thông qua tham số variable. Tham số command chỉ định phương thức nào sẽ được gọi khi check, ở đây là phương thức onClick().

cb.select()

Chúng ta sử dụng phương thức select() để thiết lập trạng thái cho check cho button.

if self.var.get() == True:
    self.master.title("Checkbutton")
else:
    self.master.title("")

Tại phương thức onClick() chúng ta cho hiện/ẩn tiêu đề cửa sổ thông qua phương thức master.title(), chúng ta kiểm tra check button có được check hay không thông qua thuộc tính self.var.

Capture

Label

Label dùng để hiển thị text hoặc hình ảnh. Trong ví dụ dưới đây, chúng ta sẽ dùng Label để hiển thị ảnh lên màn hình.

from PIL import Image, ImageTk
from tkinter import Tk, Frame, Label

class Example(Frame):
  def __init__(self, parent):
    Frame.__init__(self, parent)
 
    self.parent = parent
 
    self.initUI()
 
  def initUI(self):
    self.parent.title("Label")
 
    self.img = Image.open("C:\\tatras.jpg")
    tatras = ImageTk.PhotoImage(self.img)
    label = Label(self, image=tatras)
 
    label.image = tatras
 
    label.pack()
    self.pack()
 
  def setGeometry(self):
    w, h = self.img.size
    self.parent.geometry(("%dx%d+300+300") % (w, h))
 
root = Tk()
ex = Example(root)
ex.setGeometry()
root.mainloop()

Để chạy được ví dụ trên thì bạn phải có thư viện Pillow trong Python.

from PIL import Image, ImageTk

Mặc định thì Label trong Tkinter cũng có các module có thể hiển thị ảnh nhưng rất hạn chế.

label = Label(self, image=tatras)

Chúng ta dùng tham số image khi khởi tạo để gán ảnh vào label.

label.image = tatras

Tiếp theo bạn phải tạo một biến để giữ lại tham chiếu đến ảnh nếu không bộ thu dọn tài nguyên của Python sẽ xóa mất ảnh của chúng ta.

w, h = self.img.size
self.parent.geometry(("%dx%d+300+300") % (w, h))

Hai dòng code trên chúng ta cho kích thước màn hình bằng đúng với kích thước ảnh.

Capture

Scale

Scale là widget hiển thị một thanh cuộn gắn với một khoảng giá trị nào đó.

from tkinter import Tk, BOTH, IntVar, LEFT
from tkinter.ttk import Frame, Label, Scale, Style

class Example(Frame):
  def __init__(self, parent):
    Frame.__init__(self, parent)
    self.parent = parent
    self.initUI()
 
  def initUI(self):
    self.parent.title("Scale")
    self.style = Style()
    self.style.theme_use("default")
 
    self.pack(fill=BOTH, expand=1)
 
    scale = Scale(self, from_=0, to=100, command=self.onScale)
    scale.pack(side=LEFT, padx=15)
 
    self.var = IntVar()
    self.label = Label(self, text=0, textvariable=self.var)
    self.label.pack(side=LEFT)
 
  def onScale(self, val):
    v = int(float(val))
    self.var.set(v)
 
root = Tk()
ex = Example(root)
root.geometry("250x100+300+300")
root.mainloop()

Trong ví dụ trên chúng ta cho hiển thị một scale và một label, text trên label sẽ thay đổi khi kéo thanh cuộn trên scale.

scale = Scale(self, from_=0, to=100, command=self.onScale)

Tạo một đối tượng Scale. Hai tham số from_ và to là phạm vi giá trị của scale. Tham số command chỉ định phương thức sẽ được gọi khi di chuyển thanh cuộn.

self.var = IntVar()
self.label = Label(self, text=0, textvariable=self.var)    

Cũng giống như Checkbutton, ở đây chúng ta tạo label, một đối tượng IntVar và kết nối đối tượng đó với label bằng tham số textvariable. Giá trị của biến này sẽ được hiển thị trên label.

def onScale(self, val):
  
    v = int(float(val))
    self.var.set(v)

Khi di chuyển thanh cuộn, phương thức onScale() sẽ được gọi kèm theo giá trị hiện tại của Scale. Chúng ta chuyển đổi kiểu dữ liệu của tham số này từ sang float rồi sang int sau đó đặt làm giá trị của đối tượng IntVar và đoạn text hiển thị trên label sẽ thay đổi theo

Capture

Listbox

Listbox cho phép hiển thị một danh sách các item. Người dùng có thể chọn một hoặc nhiều item.

from tkinter.ttk import Frame, Label
from tkinter import Tk, BOTH, Listbox, StringVar, END

class Example(Frame):
  def __init__(self, parent):
    Frame.__init__(self, parent)
 
    self.parent = parent
    self.initUI()
 
  def initUI(self):
    self.parent.title("Listbox")
    self.pack(fill=BOTH, expand=1)
 
    acts = ["Scarlet Johansson", "Rachel Weiss", "Natalie Portman", "Jessica Alba"]
 
    lb = Listbox(self)
 
    for i in acts:
       lb.insert(END, i)
 
    lb.bind("<<ListboxSelect>>", self.onSelect)
 
    lb.pack(pady=15)
 
    self.var = StringVar()
    self.label = Label(self, text=0, textvariable=self.var)
    self.label.pack()
 
  def onSelect(self, val):
    sender = val.widget
    idx = sender.curselection()
    value = sender.get(idx)
 
    self.var.set(value)
 
root = Tk()
ex = Example(root)
root.geometry("300x250+300+300")
root.mainloop()

Trong ví dụ trên, chúng ta hiển thị một danh sách tên các nữ diễn viên trong Listbox. Tên được chọn sẽ được hiển thị trên một label.

lb = Listbox(self)
for i in acts:
    lb.insert(END, i)

Chúng ta tạo một đối tượng Listbox và thêm các item vào bằng phương thức insert().

lb.bind("<<ListboxSelect>>", self.onSelect)    

Khi chọn một item thì sự kiện <<ListboxSelect>> sẽ được thực thi. Chúng ta gán sự kiện này vào phương thức onSelect().

sender = val.widget

Trong phương thức onSelect() chúng ta lấy tham chiếu đến Listbox thông qua thuộc tính val.widget và gán vào biến sender.

idx = sender.curselection()

Phương thức curselection() lấy về chỉ số của item đang được chọn.

value = sender.get(idx)  
self.var.set(value)

Từ chỉ số chúng ta lấy giá trị text của item bằng phương thức get(), sau đó gán vào label.

Capture