2023年6月22日 星期四

Python 學習筆記 : Tkinter 帶捲軸 Treeview 的位置問題

最近幾天在用 Tinker 開發公司維運軟體時發現了幾個過去不曾注意的小問題, 但這些細節卻足以讓我耗掉無謂的時間在 debug 上面, 例如要幫 Treview 綁定一個右捲軸時, 捲軸居然出現在 Treeview 下方而不是右方, 重新檢視 API 說明與比對之前成功範例都沒錯啊, 怪了. 

後來我將原始碼貼給 ChatGPT 詢問到底問題出在哪裡, 原來正解是 : 捲軸必須在 TreeView 之前放置 (pack), 亦即要先呼叫捲軸的 pack(), 然後再呼叫 TreeView 的 pack(), 範例如下 :

測試 1 : 正確的 Treeview + Scrollbar 用法 : 

import tkinter as tk
from tkinter import ttk

# 建立視窗
root=tk.Tk()  # 建立視窗物件
root.title('TreeView 與 Scrollbar 測試') # 設定視窗標題
root.geometry('600x200')  # 設定視窗尺寸
# 建立捲軸與 Treeview
scrollbar=tk.Scrollbar(root)  # 建立捲軸物件
scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 卷軸必須比 Treeview 先放置
treeview=ttk.Treeview(root, columns=('country', 'continent')) # 建立 Treeview
treeview.heading('#0', text='國碼')  # 設定 icon 欄標題
treeview.heading('#1', text='國家')  # 設定第二欄標題 
treeview.heading('#2', text='洲別')  # 設定第三欄標題
# 設定 Treeview 內容 : text 是 icon 欄位, vales 是其他欄位
treeview.insert('', index=tk.END, text='81', values=['日本', '亞洲'])
treeview.insert('', index=tk.END, text='31', values=['荷蘭', '歐洲'])
treeview.insert('', index=tk.END, text='249', values=['蘇丹', '非洲'])
treeview.insert('', index=tk.END, text='886', values=['台灣', '亞洲'])
treeview.insert('', index=tk.END, text='65', values=['新加坡', '亞洲'])
treeview.insert('', index=tk.END, text='44', values=['英國', '歐洲'])
treeview.insert('', index=tk.END, text='501', values=['貝里斯', '美洲'])
treeview.insert('', index=tk.END, text='66', values=['泰國', '亞洲'])
treeview.insert('', index=tk.END, text='504', values=['宏都拉斯', '美洲'])
treeview.insert('', index=tk.END, text='850', values=['北韓', '亞洲'])
treeview.pack(fill=tk.BOTH, expand=True)  # Treeview 須在捲軸後放置
# 捲軸與 Treeview 互相綁定
treeview.config(yscrollcommand=scrollbar.set)  # Treeview 綁定右捲軸
scrollbar.config(command=treeview.yview)  # 捲軸綁定 Treeview

root.mainloop()
 
注意此處的關鍵在於 Scrollbar 須比 Treeview 先放到 root 容器中, 結果如下 :




可見捲軸正確地出現在 Treeview 右邊. 如果 pack() 的順序顛倒, 即先放 Treeview 後放 Scrollbar, 那麼 Scrollbar 會出現在 Treeview 下方, 例如 :


測試 1 : 不正確的 Treeview + Scrollbar 用法 : 

import tkinter as tk
from tkinter import ttk

# 建立視窗
root=tk.Tk()  # 建立視窗物件
root.title('TreeView 與 Scrollbar 測試') # 設定視窗標題
root.geometry('600x300')  # 設定視窗尺寸
# 建立捲軸與 Treeview
treeview=ttk.Treeview(root, columns=('country', 'continent')) # 建立 Treeview
treeview.heading('#0', text='國碼')  # 設定 icon 欄標題
treeview.heading('#1', text='國家')  # 設定第二欄標題 
treeview.heading('#2', text='洲別')  # 設定第三欄標題
# 設定 Treeview 內容 : text 是 icon 欄位, vales 是其他欄位
treeview.insert('', index=tk.END, text='81', values=['日本', '亞洲'])
treeview.insert('', index=tk.END, text='31', values=['荷蘭', '歐洲'])
treeview.insert('', index=tk.END, text='249', values=['蘇丹', '非洲'])
treeview.insert('', index=tk.END, text='886', values=['台灣', '亞洲'])
treeview.insert('', index=tk.END, text='65', values=['新加坡', '亞洲'])
treeview.insert('', index=tk.END, text='44', values=['英國', '歐洲'])
treeview.insert('', index=tk.END, text='501', values=['貝里斯', '美洲'])
treeview.insert('', index=tk.END, text='66', values=['泰國', '亞洲'])
treeview.insert('', index=tk.END, text='504', values=['宏都拉斯', '美洲'])
treeview.insert('', index=tk.END, text='850', values=['北韓', '亞洲'])
treeview.pack(fill=tk.BOTH, expand=True)  # Treeview 須在捲軸後放置
scrollbar=tk.Scrollbar(root)  # 建立捲軸物件
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)  # 卷軸比 Treeview 後放置會出現在下方
treeview.config(yscrollcommand=scrollbar.set)  # Treeview 綁定右捲軸
scrollbar.config(command=treeview.yview)  # 捲軸綁定 Treeview

root.mainloop()

此例程式碼內容與上面完全相同, 差別僅在於 Scrollbar 呼叫 pack() 順序在 Treeview 呼叫 pack() 之後, 結果捲軸會被放在 Treeview 下方, 如下圖所示 :




順序決定了位置, 人生也是如此. 

沒有留言 :