我正在使用 Python 和 Tkinter 開發一個應用程式,這個應用程式需要多種輸入形式。每個輸入表單都需要一個滾動條,以防表單的父表單太短而無法顯示所有內容,因此經過 Google 的一些幫助,這就是我目前擁有的:
import tkinter as tk
def get_vertically_scrollable_frame(parent_frame: tk.Frame or tk.Tk) -> tk.Frame:
"""
:param parent_frame: The frame to place the canvas and scrollbar onto.
:return: A scrollable tk.Frame object nested within the parent_frame object.
"""
assert isinstance(parent_frame, tk.Frame) or isinstance(parent_frame, tk.Tk)
# Create the canvas and scrollbar.
canvas = tk.Canvas(master=parent_frame, bg="blue")
scrollbar = tk.Scrollbar(master=parent_frame, orient=tk.VERTICAL, command=canvas.yview)
# Let the canvas and scrollbar resize to fit the parent_frame object.
parent_frame.rowconfigure(0, weight=1)
parent_frame.columnconfigure(0, weight=1)
canvas.grid(row=0, column=0, sticky='news')
scrollbar.grid(row=0, column=1, sticky='nes')
# Link the canvas and scrollbar together.
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', lambda x: canvas.configure(scrollregion=canvas.bbox("all")))
# Create the tk.Frame that is within the canvas.
canvas_frame = tk.Frame(master=canvas, bg="red")
canvas.create_window((0, 0), window=canvas_frame, anchor="nw")
# TODO: Let the canvas_frame object resize to fit the parent canvas.
canvas.columnconfigure(0, weight=1)
canvas.rowconfigure(0, weight=1)
# canvas_frame.grid(row=0, column=0, sticky="news") # Resizes the frame, but breaks the scrollbar.
return canvas_frame
if __name__ == "__main__":
window = tk.Tk()
window.rowconfigure(0, weight=1)
window.columnconfigure(0, weight=1)
parent_frame = tk.Frame(master=window)
parent_frame.grid(row=0, column=0, sticky="news")
scrollable_frame = get_vertically_scrollable_frame(parent_frame)
# Add the widgets to the new frame.
scrollable_frame.columnconfigure(0, weight=1) # Resize everything horizontally.
tk.Label(master=scrollable_frame, text="First name").grid(row=0, column=0, sticky="w")
tk.Entry(master=scrollable_frame).grid(row=1, column=0, sticky="ew")
tk.Label(master=scrollable_frame, text="").grid(row=2, column=0, sticky="w")
tk.Label(master=scrollable_frame, text="Last name").grid(row=3, column=0, sticky="w")
tk.Entry(master=scrollable_frame).grid(row=4, column=0, sticky="ew")
tk.Label(master=scrollable_frame, text="").grid(row=5, column=0, sticky="w")
tk.Label(master=scrollable_frame, text="Email").grid(row=6, column=0, sticky="w")
tk.Entry(master=scrollable_frame).grid(row=7, column=0, sticky="ew")
tk.Label(master=scrollable_frame, text="").grid(row=8, column=0, sticky="w")
tk.Label(master=scrollable_frame, text="Favorite color").grid(row=9, column=0, sticky="w")
tk.Entry(master=scrollable_frame).grid(row=10, column=0, sticky="ew")
tk.Label(master=scrollable_frame, text="").grid(row=11, column=0, sticky="w")
tk.Frame(master=scrollable_frame).grid(row=12, column=0, sticky="news")
scrollable_frame.rowconfigure(12, weight=1) # Vertically resize filler frame from last line.
tk.Button(master=scrollable_frame, text="Clear").grid(row=13, column=0, sticky="ews")
tk.Button(master=scrollable_frame, text="Submit").grid(row=14, column=0, sticky="ews")
window.mainloop()
此函式采用一個空的 Tkinter 框架,在該框架上放置一個作業畫布和滾動條,將一個新框架放入畫布中,然后回傳畫布內的框架。
雖然滾動條與上述代碼配合良好,但回傳的嵌套 Tkinter 框架不會調整大小以適應其父畫布的高度和寬度。如果父畫布太大,它看起來像這樣:


(藍色區域是畫布,紅色是畫布內的框架。)
為了解決這個問題,我使用 grid 手動將嵌套框架放置在畫布上(請參閱 return 陳述句之前的注釋代碼)。畫布內的框架開始自行調整大小,但滾動條停止作業。


有沒有一種簡單的方法可以讓畫布內的框架在不破壞滾動條的情況下調整自身大小?
uj5u.com熱心網友回復:
有沒有一種簡單的方法可以讓畫布內的框架在不破壞滾動條的情況下調整自身大小?
簡單的?我想這取決于您對簡單性的定義。這是可能的,但它需要一些額外的代碼行。
只有當您將框架添加到畫布時create_window,滾動條才起作用,并且僅當您讓框架變得盡可能大以容納其所有子項,然后相應地設定畫布 bbox。當視窗調整大小時,如果框架小于畫布,您需要強制框架大于它想要的大小,但如果框架大于畫布,則需要讓框架成為其首選大小。
該解決方案類似于以下示例,在我的腦海中。請注意使用標簽可以輕松找到內部框架。您可以輕松地存盤回傳的 idcreate_window并使用它。這也充分利用了這一事實的優點event物件具有width和height在畫布屬性。
def get_vertically_scrollable_frame(parent_frame: tk.Frame or tk.Tk) -> tk.Frame:
...
canvas.create_window((0, 0), window=canvas_frame, anchor="nw", tags=("canvas_frame",))
canvas.bind('<Configure>', handle_resize)
...
def handle_resize(event):
canvas = event.widget
canvas_frame = canvas.nametowidget(canvas.itemcget("canvas_frame", "window"))
min_width = canvas_frame.winfo_reqwidth()
min_height = canvas_frame.winfo_reqheight()
if min_width < event.width:
canvas.itemconfigure("canvas_frame", width=event.width)
if min_height < event.height:
canvas.itemconfigure("canvas_frame", height=event.height)
canvas.configure(scrollregion=canvas.bbox("all"))
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/323851.html
