前面介紹的Label、Entry、Combobox…等元件,每個元件一次只能顯示或編輯「一筆」資料。但實務上常常需要一次顯示「多筆、多欄位」的資料,例如查詢資料庫後要把所有學生資料列成一張表格,這時候如果每一筆資料都用一排Label來顯示,不但寫起來麻煩,畫面也不好管理。
ttk模組提供的Treeview元件,可以用「表格」的方式一次顯示多欄、多列資料(類似Excel工作表或Windows檔案總管的詳細資料檢視),並支援讓使用者點選其中一列。建立語法如下:
物件變數 = ttk.Treeview(容器物件, columns=(欄位代號1, 欄位代號2, …), show='headings', [其他參數])建立步驟
與前面的元件不同,Treeview通常需要下面幾個步驟才能組成一張完整的表格:
- 建立
Treeview物件:透過columns參數指定每一欄的「欄位代號」(供程式內部識別用,不會直接顯示在畫面上),show='headings'表示只顯示自訂的欄位標題列,隱藏tkinter預設會顯示的第一個樹狀縮排欄位(因為這裡只需要平面表格,不需要樹狀結構)。 - 設定欄位標題:對每個欄位呼叫
heading(欄位代號, text=標題文字),設定該欄在畫面上顯示的標題文字。 - 設定欄位寬度與對齊:對每個欄位呼叫
column(欄位代號, width=寬度, anchor=對齊方式),anchor可指定'center'(置中)、'w'(靠左)、'e'(靠右)等。 - 新增資料列:呼叫
insert(父節點, 位置, values=(值1, 值2, …))新增一列資料。由於這裡不使用樹狀結構,父節點固定給空字串''(代表最上層),位置通常給'end'表示插入到清單最後面。
常用方法
| 方法 | 說明 |
|---|---|
heading(欄位代號, text=標題) | 設定指定欄位的標題文字。 |
column(欄位代號, width=寬度, anchor=對齊) | 設定指定欄位的寬度與對齊方式。 |
insert(父節點, 位置, values=(值,...)) | 新增一列資料,values的順序須對應columns參數的欄位順序。 |
get_children() | 取得目前清單中所有列的識別碼(item id),常搭配迴圈用來走訪或清空所有資料列。 |
delete(item_id) | 刪除指定識別碼的那一列資料。 |
item(item_id, 'values') | 取得(或設定)指定列目前的資料內容。 |
selection() | 取得目前使用者選取的列識別碼(可能有多筆,回傳為tuple)。 |
selection_remove(item_id, ...) | 取消指定列的選取狀態。 |
[簡例] 清空並重新載入清單資料時,常見寫法是先用get_children()取出所有列、逐一delete(),再重新insert()一次,避免舊資料與新資料重複顯示:
for row in tree.get_children():
tree.delete(row)
for row in 資料來源:
tree.insert('', 'end', values=row)事件綁定:bind() 與 <<TreeviewSelect>>
前面Button、Radiobutton、Checkbutton都是用command參數指定「按下/狀態改變時」要執行的函式,但Treeview本身沒有command參數,因為「使用者選取某一列」是Treeview特有的動作,必須改用所有tkinter元件都通用的bind()方法來監聽事件:
物件變數.bind(事件名稱, 處理函式)Treeview在使用者選取(或改變選取)某一列時,會觸發tkinter內建的「虛擬事件」'<<TreeviewSelect>>',因此只要用bind()把這個事件綁定到自訂函式即可:
def on_select(event):
selected = tree.selection()
if not selected:
return
...
tree.bind('<<TreeviewSelect>>', on_select)綁定事件的處理函式(如上面的on_select)都必須固定接收一個event參數,這個參數是由tkinter在事件觸發時自動傳入的物件,內含事件相關資訊;即使函式內用不到event的內容,也不能省略這個參數。
[簡例] 建立一張成績清單表格,使用者點選某一列時,把該列姓名與成績帶出並顯示在下方標籤。(檔名:treeview01.py)
程式碼:
treeview01.pyimport tkinter as tk from tkinter import ttk win = tk.Tk() win.title('Treeview 範例') win.geometry('420x220') columns = ('id', 'name', 'score') tree = ttk.Treeview(win, columns=columns, show='headings', height=6) tree.heading('id', text='座號') tree.heading('name', text='姓名') tree.heading('score', text='成績') tree.column('id', width=60, anchor='center') tree.column('name', width=100, anchor='center') tree.column('score', width=80, anchor='center') tree.pack(fill='both', expand=True, padx=10, pady=10) data = [(1, '小明', 88), (2, '小美', 92), (3, '小華', 76)] for row in data: tree.insert('', 'end', values=row) lblResult = tk.Label(win, text='請點選清單中的一列') lblResult.pack() def on_select(event): selected = tree.selection() if not selected: return cid, name, score = tree.item(selected[0], 'values') lblResult['text'] = f'你選取了 {name} 同學,成績 {score} 分' tree.bind('<<TreeviewSelect>>', on_select) win.mainloop()
[結果]
(可自行執行程式碼查看畫面:上方為三欄成績表格,點選任一列後下方標籤會顯示該列姓名與成績。)
說明
- 第
8~9行:建立tree這個Treeview,columns指定id、name、score三個欄位代號,show='headings'隱藏預設的樹狀欄位。- 第
10~15行:分別用heading()設定三欄的標題文字,用column()設定欄寬與置中對齊。- 第
18~20行:用迴圈把data串列中的每一筆資料,依序用insert('', 'end', values=row)新增到清單最後面。- 第
25~30行:定義on_select()函式,用tree.selection()取得目前選取的列,再用tree.item(選取id, 'values')取出該列的(座號, 姓名, 成績)資料。- 第
32行:用bind('<<TreeviewSelect>>', on_select)把「選取清單項目」事件綁定到on_select()函式,之後只要使用者點選清單中的任一列就會自動觸發。
在 student_crud.py 的應用
student_crud.py的_build_tree()、refresh()、on_select()三個方法就是這裡介紹方法的完整實際應用:
_build_tree():建立self.tree並設定 7 個欄位(cID、cName、cSex、cBirthday、cEmail、cPhone、cAddr)的標題與寬度,並用bind('<<TreeviewSelect>>', self.on_select)綁定選取事件。refresh():每次重新查詢資料庫後,先用get_children()+delete()清空清單,再依查詢結果逐筆insert(),確保畫面永遠反映資料庫最新內容。on_select():使用者點選某一列時,用selection()取得選取的列,再用item(選取id, 'values')取出該列資料填回上方表單,並記錄self.selected_id供「修改」/「刪除」使用。
相關主題與延伸閱讀
- 0. 章節索引:本章全部筆記的學習地圖與快速查找。
- 1. tkinter 套件:
tkinter套件的整體介紹與元件總覽。 - 11. ttk 主題元件套件:
Treeview是ttk模組獨有、tkinter本身沒有的元件。 - 3. 視窗版面配置:
pack02.py範例即示範Treeview搭配fill='both', expand=True排版。 - 12. Frame 與 LabelFrame 容器元件:
student_crud.py中Treeview常與容器元件一起組成完整畫面。 - 3. 自定函式:
bind()綁定的事件處理函式(如on_select)即為自定函式,須固定接收event參數。