2021年9月7日 星期二

Python 內建 GUI 模組 tkinter 測試 (十一) : Listbox 元件



Listbox 元件也是一種選項元件, 用來顯示一份可讓使用者挑選的清單, 可以單選也可以複選 (透過 selectmode 參數). 注意, 此元件僅在 tk 中有, ttk 中無此元件. 建立 Listbox 元件之語法如下 : 

Listbox(父容器, **參數列)



Listbox 元件常用參數如下表 : 


 Listbox 常用參數 說明
 width 寬度 (單位=字元數, 預設=10)
 height 高度 (單位=字元數, 預設=20)
 bg/background 背景色, 可用標準顏色名稱字串例如 'blue' 或 "#0000ff"
 selectmode 選取模式=BROWSE(預設)/SINGLE/MULTIPLE/EXTENDED
 xscrollcommand 用來綁定之水平捲軸之 set() 方法, 使 Listbox 加上水平捲軸
 yscrollcommand 用來綁定之垂直捲軸之 set() 方法, 使 Listbox 加垂直平捲軸
 listvariable 用來綁定一個類別變數以便動態存取 Listbox 內容
 selectbackground 被選取項目背景色, 可用標準顏色名稱字串例如 'blue' 或 "#0000ff"


可見 Listbox 並沒有 command 參數可直接綁定一個動作函式, 故需要搭配 Button 元件使用. 

其中 selectmode 用來設定 Listbox 模式, 預設為 tk.BROWSE, 此模式為單選可拖曳, 即選取某項幕後若按住左鍵拖曳滑過其他項目, 會自動改為選取所滑過之項目. 設定為 tk.SINGLE 也是只能單選, 但點選後拖曳時不會自動改變被選取項目. 設為 tk.MULTIPLE 可點選多個選項, 而 tk.EXTENDED 則是可搭配 Shift 鍵進行區間複選. 

Listbox 可加上 Scrollbar 捲軸, 此時就需要用到 xscrollcommand 或 yscrollcommand 了, 將其設定為呼叫 Scrollbar 物件的 set() 方法即可為 Listbox 加上水平或垂直捲軸, 但也要在 Scrollbar 元件上用 command 參數來呼叫 Listbox 元件的 xview() 或 yview() 方法, 這樣捲動捲軸時 Listbox 的項目才會同步被捲動. 

Listbox 元件常用方法如下表 :


 Listbox 常用方法 說明
 insert(index, option) 將選項 option 加入 Listbox 指定索引 index
 delete(first [, last]) 刪除索引 first~last 之間的項目 (無 last 時僅刪除 first)
 get(first [, last]) 以元組傳回索引 first~last 間的項目 (無 last 時僅傳回 first)
 size() 傳回項目總數
 curselection() 以元組傳回被選取之項目索引, 單選時傳回 (idx,) 
 xscrollcommand() 用來綁定之水平捲軸之 set 方法
 yscrollcommand() 用來綁定之垂直捲軸之 set 方法
 activate(index) 使索引位置為 index 之項目被選取
 selection_set(idx) 設定索引為 idx 之項目為被選取狀態
 selection_includes(idx) 檢查所傳入之索引項目是否有被選取 (True/False)
 xview() 給 Scrollbar 元件之 command 參數呼叫, 為 Listbox 加上水平捲軸
 yview() 給 Scrollbar 元件之 command 參數呼叫, 為 Listbox 加上垂直捲軸


其中最常用的 curselection() 方法會以元組形式傳回被選取的項目索引, 以迴圈走訪並利用 get() 方法即可取得被選取之項目. 另外, xview() 與 yview() 不用於實際呼叫, 而是用來給 Scrollbar 元件的 command 參數呼叫, 這樣當 Scrollbar 捲動時, Listbox 中的項目才會隨之捲動. 


測試 1 : 用參數 listvariable 綁定類別變數 (1) [看原始碼]

import tkinter as tk
from tkinter import ttk

def show_selection():
    result_label["text"]=var.get()

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()        # 用來動態取得 Listbox 選項
listbox=tk.Listbox(win, bg="cyan", listvariable=var)    # 綁定類別變數
listbox.insert(0, "Python")
listbox.insert(1, "Javascript")
listbox.insert(2, "R")
listbox.insert(3, "Julia")
listbox.pack()
tk.Button(win, text="確定", command=show_selection).pack()
result_label=tk.Label(win)
result_label.pack()
win.mainloop()

此例建立了一個 Listbox 物件並呼叫其 indert() 方法加入四個選項, 同時使用 listvariable 參數與類別變數 var 綁定, 但透過此類別變數的 get() 所取得的並非被選定的項目, 而是以 tuple 形式傳回全部的選項, 結果如下 :




Listbox 預設選取模式為 BROWSE 模式 (單選), 以滑鼠點選某項目後若移動滑鼠, 則被選取項目將持續變更為滑過之項目, 滑鼠停駐的那個項目就是最後被選取項目. 

另外, 由此例可知透過與 listvariable 綁定的類別變數取得的是 Listbox 的全部選項, 因此除了可用 Listbox 物件的 insert() 方法設定選項外, 也可以呼叫類別變數的 set() 方法並傳入項目元組或串列來一次設定好 Listbox 的全部選項, 例如 :


測試 2 : 用參數 listvariable 綁定類別變數 (2) [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_listvariable():
    result_label["text"]=var.get()
def set_listvariable():
    var.set(("Python", "Javascript", "R", "Julia"))    #設定選項

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
listbox=tk.Listbox(win, bg="cyan", listvariable=var, height=8)
listbox.pack()
tk.Button(win, text="設定", command=set_listvariable).pack()
tk.Button(win, text="確定", command=get_listvariable).pack()
result_label=tk.Label(win)
result_label.pack()
win.mainloop()

此例增加了一個 "設定" 鈕, 按下會呼叫 set_listvariable() 函式將選項 tuple 傳入類別變數的 set() 方法設定 Listbox 的選項, 結果如下 : 






可見當程式執行時 Listbox 內並無任何選項, 按下設定鈕後才會出現選項. 除了使用 listvariable 外, 也可以透過 Listbox 物件的 size() 與 get() 方法取得全部選項內容, 例如 : 


測試 3 : 用 size() 與 get() 方法取得 Listbox 全部選項 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_options():
    size=listbox.size()                     # 取得選項總數
    options=listbox.get(0, size)      # 取得全部選項 (tuple)
    result_label["text"]="size=" + str(size) + " " + str(options)    #呼叫 str() 字串化

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))      #設定選項
listbox=tk.Listbox(win, bg="cyan", listvariable=var, height=8)    
listbox.pack()
tk.Button(win, text="確定", command=get_options).pack()
result_label=tk.Label(win)
result_label.pack()
win.mainloop()

此例先使用 Listbox 物件的 size() 方法取得選項總數, 然後將其傳給 get() 方法的第二參數即可取得全部選項內容之元組, 結果如下 : 




如果要取得使用者選取的選項則需利用 Listbox 物件的 curselection() 方法, 例如 : 


測試 4 : 用 curselection() 方法取得被選取之選項 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_selected_option():
    selected=listbox.curselection()      # 傳回被選取之項目索引 (tuple)
    result_label["text"]="curselection=" + str(selected) + \
                         " 選取: " + listbox.get(selected[0])

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, height=8)
listbox.pack()
tk.Button(win, text="確定", command=get_selected_option).pack()
result_label=tk.Label(win)
result_label.pack()
win.mainloop()

此例利用 Listbox 的 curselection() 方法取得被選取項目之索引, 由於預設是單選, 故其傳回值為單一元素之元組例如 (2,), 只要將索引傳入 get() 即可取得被選取項目, 結果如下 :




上面範例的 Listbox 均為預設 BROWSE 模式 (單選), 如果要可複選需將 selectmode 參數設定為 MULTIPLE, 例如 :


測試 5 : 將 selectmode 參數設為 MULTIPLE 可複選模式 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_selected_options():
    selected=listbox.curselection()      #傳回被選取項目索引 tuple
    label_1.config(text="curselection=" + str(selected))
    selected_options=[]     #儲存被選取之選項
    for i in selected:           #走訪被選取之項目索引
        selected_options.append(listbox.get(i))         #取得項目內容放入串列
    label_2["text"]=" 選取: " + ",".join(selected_options)    #以逗號串接選項

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, selectmode="multiple")  #可複選
listbox.pack()
tk.Button(win, text="確定", command=get_selected_options).pack()
label_1=tk.Label(win)
label_1.pack()
label_2=tk.Label(win)
label_2.pack()
win.mainloop()

此例在建立 Listbox 物件時即以 selectmode="multiple" (亦可用 tk.MULTIPLE) 將選取模式設為可複選, 因此呼叫 curselection() 時將傳回被選取項目索引組成之 tuple, 欲取得被選取項目必須用迴圈走訪此 tuple, 然後將迭代之索引傳入 Listbox 物件的 get() 方法, 並將取得之被選取項目放入串列中存放, 結果如下 : 




注意, MULTIPLE 複選模式直接用滑鼠點選即可, 不需要 CTRL 鍵配合. 複選模式除 MULTIPLE 外還有 EXTENDED 模式, 此模式下可用 Shift 鍵進行區間選取, 例如 :


測試 6 : 將 selectmode 參數設為 EXTENDE 區間可複選模式 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_selected_options():
    selected=listbox.curselection()
    label_1.config(text="curselection=" + str(selected))
    selected_options=[]
    for i in selected:
        selected_options.append(listbox.get(i))
    label_2["text"]=" 選取: " + ",".join(selected_options)

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, selectmode=tk.EXTENDED)  #區間
listbox.pack()
tk.Button(win, text="確定", command=get_selected_options).pack()
label_1=tk.Label(win)
label_1.pack()
label_2=tk.Label(win)
label_2.pack()
win.mainloop()

此例與上例唯一的差別為 selectmode 改為 tk.EXTENDED (也可以用 "extended"), 先點選某一選項, 然後按住 Shift 鍵再點選另一選項, 則兩個選項之間的選項全部都會被選取, 結果如下 : 



此為點選選項 1 (Python) 後按住 Shift 鍵再點選選項 4 (Julia) 的結果, 可見全部選項都選取了. 下面範例則是 SINGLE 選取模式 : 


測試 7 : 將 selectmode 參數設為 SINGLE 單選模式 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_selected_options():
    selected=listbox.curselection()
    label_1.config(text="curselection=" + str(selected))
    selected_options=[]
    for i in selected:
        selected_options.append(listbox.get(i))
    label_2["text"]=" 選取: " + ",".join(selected_options)

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, selectmode="single")   #單選無拖曳
listbox.pack()
tk.Button(win, text="確定", command=get_selected_options).pack()
label_1=tk.Label(win)
label_1.pack()
label_2=tk.Label(win)
label_2.pack()
win.mainloop()

此例與上兩例唯一差別也是 selectmode, 此處設為 "single" (用 tk.SINGLE 亦可) 表示為單選不可拖曳, 亦即當點選某項目後, 即使滑鼠滑過其他選項也不會自動變更被選取項目, 必須用滑鼠去點選才會變更, 結果如下 : 




下面範例測試 selection_set() 方法, 此方法可將傳入之索引項目設為被選取狀態. 此方法不須攔截例外, 因為即使索引值超出項目索引範圍也不會出現錯誤, 只是沒有選取效果而已 :


測試 8 : 用 selection_set() 設定被選取項目 [看原始碼]

import tkinter as tk
from tkinter import ttk

def get_selected_options():
    selected=listbox.curselection()
    label_1.config(text="curselection=" + str(selected))
    selected_options=[]
    for i in selected:
        selected_options.append(listbox.get(i))
    label_2["text"]=" 選取: " + ",".join(selected_options)

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var)
listbox.selection_set(1)    #將索引 1 之項目設為被選取狀態
listbox.pack()
tk.Button(win, text="確定", command=get_selected_options).pack()
label_1=tk.Label(win)
label_1.pack()
label_2=tk.Label(win)
label_2.pack()
win.mainloop()

此例在建立 Listbox 物件並初始化 (即新增項目後) 呼叫其 selection_set() 方法將索引為 1 的項目 (Javascript) 設為被選取狀態, 結果如下 : 




可見程式一執行, 索引 1 的項目就已被選取了. 下面範例測試 selection_includes() 方法 :


測試 9 : 用 selection_includes() 檢查指定的索引項目是否被選取 [看原始碼]

import tkinter as tk
from tkinter import ttk

def check_selection():
    label["text"]="selection_includes(2)=" + str(listbox.selection_includes(2))

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, selectmode="multiple")
listbox.pack()
tk.Button(win, text="確定", command=check_selection).pack()
label=tk.Label(win)
label.pack()
win.mainloop()

此例將 Listbox 設為 MULTIPLE 複選模式, 按下確定鈕時呼叫 Listbox 的 selection_includes() 方法檢查索引 2 的項目 (R) 是否有被選取, 其傳回值為 True (選取)/False (未選取), 結果如下 : 





可見當 R 有被選取時傳回 True, 否則傳回 False.

下面範例測試 delete() 方法, 此方法會將傳入索引的項目刪除, 即使索引不存在也不會出現錯誤 (只是沒反應而已), 因此也不需做例外處理, 例如 : 


測試 10 : 用 delete() 刪除指定的索引項目 [看原始碼]

import tkinter as tk
from tkinter import ttk

def reset_listbox():
    var.set(("Python", "Javascript", "R", "Julia"))
def delete_option():
    listbox.delete(0)      #刪除索引 0 之項目

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

var=tk.StringVar()
var.set(("Python", "Javascript", "R", "Julia"))
listbox=tk.Listbox(win, bg="cyan", listvariable=var, selectmode="multiple")
listbox.pack()
tk.Button(win, text="重設", command=reset_listbox).pack()     #重設 Listbox
tk.Button(win, text="刪除", command=delete_option).pack()    #刪除 Listbox 項目索引 0
label=tk.Label(win)
label.pack()
win.mainloop()

此例按下刪除鈕會呼叫 Listbox 的 delete() 方法固定刪除索引 0 之項目, 刪除後其餘項目會自動往前移, 因此都存在索引 0 項目直到全部項目都已刪掉. 任何時候按重設鈕則將 Listbox 恢復原狀, 結果如下 :  





下面是用 insert() 新增後可點選項目刪除的範例 : 


測試 11 : 預設 BROWSE 選取模式下的項目刪除 [看原始碼]

import tkinter as tk
from tkinter import ttk

def add_option():
    listbox.insert(0, option.get())      # 從類別變數取得 Entry 輸入新增項目
def delete_option():
    listbox.delete(listbox.curselection())    # 刪除目前被選取之項目

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x350")

listbox=tk.Listbox(win, bg="cyan")
listbox.pack()
option=tk.StringVar()        # 輸入待新增項目
tk.Entry(win, textvariable=option).pack()  
tk.Button(win, text="新增", command=add_option).pack()
tk.Button(win, text="刪除", command=delete_option).pack()
label=tk.Label(win)
label.pack()
win.mainloop()

此例 Listbox 為預設的 BROWSE 模式, 即滑鼠移動時會自動改變單一選取項目. 此處使用一個 Entry 用來輸入要新增的項目, 並將其綁定到類別變數 option, 按下新增鈕會先呼叫其 get() 方法取得欲新增之項目, 然後呼叫 Listbox 的 insert() 方法新增項目. 如果 Entry 內沒有輸入項目, 則會新增一個空字串項目. 刪除時需先用滑鼠點選欲刪除之項目後按刪除鈕, 然後呼叫 Listbox 的 curselection() 方法取得其索引, 再將其傳給 Listbox 的 delete() 方法, 結果如下 :




下面是 MULTIPLE 選取模式 (複選無拖曳) 下的項目刪除方式, 因為此模式下項目是要用滑鼠一個一個點選, 這些項目可能連續也可能不連續, 且刪除一個項目後剩下的項目索引會往上移一格, 因此用迴圈刪除多個項目時應從索引大者開始刪, 因此透過 curselection() 傳回的被選取項目元組要轉換成串列, 再呼叫 sort() 方法做遞減排序, 這樣才能做到在迴圈中從後面往前刪除, 例如 : 


測試 12 : MULTIPLE 選取模式下的項目刪除 [看原始碼]

import tkinter as tk
from tkinter import ttk

def add_option():
    listbox.insert(0, option.get())
def delete_options():   
    selected=list(listbox.curselection())      # 將被選取的複選項目索引元組轉成串列
    selected.sort(reverse=True)                # 遞減排序
    for i in selected:          
        listbox.delete(i)                                 # 從索引較大的開始刪

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x400")

listbox=tk.Listbox(win, bg="cyan", selectmode=tk.MULTIPLE)  # 複選無拖曳
listbox.pack()
option=tk.StringVar()
tk.Entry(win, textvariable=option).pack()
tk.Button(win, text="新增", command=add_option).pack()
tk.Button(win, text="刪除", command=delete_options).pack()
label=tk.Label(win)
label.pack()
win.mainloop()

此例將 Listbox 設為 MULTIPLE 模式, 即可複選但無拖曳功能, 每個選項需滑鼠一個個點選, 因被選取項目可能連續也可能不連續, 因此刪除時須從索引大者開始刪, 才不會因為索引遞補而刪錯項目, 結果如下 : 





EXTENDED 選取模式 (可用 Shift 鍵做連續範圍選取, 但無拖曳功能) 的刪除方式則較為簡單, 只要連續刪除被選取選項的第一個索引選項即可, 因為選項被刪除後索引會往前遞補之故, 例如 :


測試 13 : EXTENDED 選取模式下的項目刪除 [看原始碼]

import tkinter as tk
from tkinter import ttk

def add_option():
    listbox.insert(0, option.get())
def delete_options():
    selected=listbox.curselection()     # 傳回被選取選項之索引 (tuple)
    for i in selected:                              # 走訪元組
        listbox.delete(selected[0])          # 固定刪除元組中第一個索引之項目

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")
win.geometry("400x400")

listbox=tk.Listbox(win, bg="cyan", selectmode=tk.EXTENDED)    #連續範圍選取
listbox.pack()
option=tk.StringVar()
tk.Entry(win, textvariable=option).pack()
tk.Button(win, text="新增", command=add_option).pack()
tk.Button(win, text="刪除", command=delete_options).pack()
label=tk.Label(win)
label.pack()
win.mainloop()

此例的 Listbox 選取模式設定為 EXTENDED (用 Shift 鍵連續範圍選取), 與上例差異為刪除函式 delete_options() 的做法, 此處在走訪被選取選項的索引元組 selected 時, 不可將迭代變數傳入 delete() 方法, 因為那只有在刪除選取範圍的第一個索引是正確的, 刪除它後整個後面的索引會往上遞補, 這會跳過應該刪除之選項. 正確做法是只要固定刪除被選取範圍的第一個元素即可, 結果如下 : 





下面是利用 insert() 與 delete() 方法在兩個 Listbox 之間傳遞選項的範例 : 


測試 14 : 兩個 Listbox 互相傳遞選項 [看原始碼]

import tkinter as tk
from tkinter import ttk

def move_left():
    for i in listbox_2.curselection():              # 走訪被選取項目元組   
        listbox_1.insert(0, listbox_2.get(i))     # 加入左方 Listbox
        listbox_2.delete(i)                                # 從右方 Listbox 中移除
def move_right():
    for i in listbox_1.curselection():              # 走訪被選取項目元組
        listbox_2.insert(0, listbox_1.get(i))     # 加入右方 Listbox
        listbox_1.delete(i)                                # 從左方 Listbox 中移除

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")

listbox_1=tk.Listbox(win, bg="cyan")                        # 左邊 Listbox
names=('張無忌', '趙敏', '周芷若', '小昭', '殷離', '楊不悔', '朱九貞')    # 選項
for name in names:                       # 將選項寫入左邊 Listbox
    listbox_1.insert(0, name)
listbox_1.grid(row=0, column=0, rowspan=2)             # 右邊 Listbox
tk.Button(win, text=">>", command=move_right).grid(row=0, column=1)
tk.Button(win, text="<<", command=move_left).grid(row=1, column=1)
listbox_2=tk.Listbox(win, bg="ivory")
listbox_2.grid(row=0, column=2, rowspan=2)
win.mainloop()

此例使用 grid 版面管理員將視窗分為 2x3 方格版面, 兩個 Listbox 放在左右 (用 rowspan 合併垂直儲存格), 兩個按鈕則放在中間,  當按下右移鈕時呼叫 move_right(), 先用 curselection() 取得被選取項目之元組, 然後以迴圈走訪此元組, 先將被選取項目添加到右方 Listbox, 然後再將此項目從左方 Listbox 中移除. 反之左移時也是如此, 只是方向相反罷了, 結果如下 : 





注意, 此處因 Listbox 都使用預設單選的 BROWSE 模式, 故 curselection() 傳回的只是單一元素之元組, 不過為了使函式較普遍化 (即可用在複選模式), 此處仍以迴圈處理. 

最後來測試 Listbox 與 Scrollbar 的組合, Listbox 可以加上 Scrollbar, 這樣當選項超過高度時可以利用捲軸來捲動選項, 這需要用到 Listbox 的 xscrollcommand 與 yscrollcommand 參數, 只要將其設定為呼叫 Scrollbar 元件的 set() 方法即可為 Listbox 套上捲軸, 但 Scrollbar 元件的 command 參數也必須設定為呼叫 Listbox 的 xview() 或 yview() 方法, 如此拉動捲軸時 Listbox 的選項才會同步捲動, 關於 Scrollbar 元件用法參考 : 


由於 Listbox 的選項通常是垂直顯示, 故最常使用的是垂直捲軸, 亦即要用到 Listbox 的 yscrollcommand 參數, 而 Scrollbar 元件之 command 參數要呼叫 Listbox 的 yview() 方法, 例如 :


測試 15 : 用 yscrollcommand 參數為 Listbox 元件加上垂直捲軸 [看原始碼]

import tkinter as tk
from tkinter import ttk

win=tk.Tk()                                                      
win.title("tkinter GUI 測試")

options=tk.StringVar()
options.set(["你是在說哈囉嗎? " + str(i) for i in range(20)])   # 設定選項
listbox=tk.Listbox(win, bg="cyan", listvariable=options)
listbox.pack(side=tk.LEFT, fill=tk.Y)                     # Listbox 靠左填滿 Y 軸
scrollbar=tk.Scrollbar(win)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)               # Scrollbar 靠右填滿 Y 軸
listbox.config(yscrollcommand=scrollbar.set)      # 加上垂直捲軸
scrollbar.config(command=listbox.yview)            # 同步捲動 Listbox 的選項
win.mainloop()

此例取消了 geometry() 的視窗尺寸設定, 讓 Listbox 與 Scrollbar 元件一個靠左一個靠右都填滿視窗 Y 軸. 此處使用串列成式在 Listbox 內添加了 20 個選項使其超出預設高度讓捲軸可捲動. 注意, 因為 command 與 yscrollcommand 這兩個參數要做雙向綁定, 因此最好另外用 config() 去設定, 而非在建立 Listbox 與 Scrollbar 物件時直接傳入參數, 以免參照錯誤, 結果如下 :




沒有留言 :