[英]Scrollable frame class in tkinter
我在 tkinter 中實現了我自己的可滾動框架 class:
class scrolledFrame(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self)
self.canvas.pack(fill = "both", expand = True, side = "left")
self.scroll = tk.Scrollbar(self, command = self.canvas.yview)
self.scroll.pack(side = "right", fill = "y")
self.canvas.config(yscrollcommand = self.scroll.set)
self.content = tk.Frame(self.canvas)
self.content.bind("<Configure>", self.resizeCanvas)
self.contentWindow = self.canvas.create_window((0,0), window = self.content, anchor = "nw")
self.content.bind("<Enter>", self.enableScrollCanvas)
self.content.bind("<Leave>", self.disableScrollCanvas)
def scrollCanvas(self, event):
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
def enableScrollCanvas(self, event):
self.canvas.bind_all("<MouseWheel>", self.scrollCanvas)
def disableScrollCanvas(self, event):
self.canvas.unbind_all("<MouseWheel>")
def resizeCanvas(self, event):
self.update_idletasks()
self.canvas.config(scrollregion = self.canvas.bbox("all"))
self.canvas.itemconfig(self.contentWindow, width = self.canvas.winfo_width())
root = tk.Tk()
exampleFrame = scrolledFrame(root)
exampleFrame.pack()
exampleLabel = tk.Label(exampleFrame.content, text = "I'm in the scrolled frame!")
exampleLabel.pack()
root.mainloop()
這工作正常,但問題是將小部件添加到滾動框架,父級必須是exampleFrame.content
。 我查看了其他幾個具有相同限制的示例。 是否可以配置 class 以便exampleFrame
可以是小部件的父級而不是exampleFrame.content
? 提前致謝。
如果你不介意一點詭計,你可以模擬你想要的。 不過,這有點駭人聽聞。
訣竅是,當您調用tk.Frame.__init__
時,您需要將 canvas 作為父級,使self
成為內容框架。 當然,要做到這一點,你必須先創建 canvas,然后創建 canvas,你必須創建外框。
它看起來像這樣:
class scrolledFrame(tk.Frame):
def __init__(self, parent):
self.outer = tk.Frame(parent)
self.canvas = tk.Canvas(self.outer)
self.scroll = tk.Scrollbar(self.outer, command = self.canvas.yview)
tk.Frame.__init__(self, self.canvas)
self.contentWindow = self.canvas.create_window((0,0), window = self, anchor = "nw")
但是,當您執行上述操作並嘗試在scrolledFrame
的實例上調用pack
、 place
或grid
時,它會做錯事,因為實例指向內部框架而不是外部框架。
詭計如下:解決方案是將對pack
、 place
和grid
的調用重定向到外框。
class scrolledFrame(tk.Frame):
def __init__(self, parent):
...
self.pack = self.outer.pack
self.place = self.outer.place
self.grid = self.outer.grid
這樣,您就可以隨意使用scrolledFrame
,只要在將其添加到布局時使用pack
、 place
或grid
。
exampleFrame = scrolledFrame(root)
exampleFrame.pack(fill="both", expand=True)
for i in range(100):
exampleLabel = tk.Label(exampleFrame, text = f"I'm in the scrolled frame! ({i})")
exampleLabel.pack()
這是一個完整的工作示例,盡管為簡潔起見,我刪除了鼠標滾輪代碼。
import tkinter as tk
class scrolledFrame(tk.Frame):
def __init__(self, parent):
self.outer = tk.Frame(parent)
self.canvas = tk.Canvas(self.outer)
self.scroll = tk.Scrollbar(self.outer, command = self.canvas.yview)
tk.Frame.__init__(self, self.canvas)
self.contentWindow = self.canvas.create_window((0,0), window = self, anchor = "nw")
self.canvas.pack(fill = "both", expand = True, side = "left")
self.scroll.pack(side = "right", fill = "y")
self.canvas.config(yscrollcommand = self.scroll.set)
self.bind("<Configure>", self.resizeCanvas)
self.pack = self.outer.pack
self.place = self.outer.place
self.grid = self.outer.grid
def resizeCanvas(self, event):
self.canvas.config(scrollregion = self.canvas.bbox("all"))
self.canvas.itemconfig(self.contentWindow, width = self.canvas.winfo_width())
root = tk.Tk()
exampleFrame = scrolledFrame(root)
exampleFrame.pack(fill="both", expand=True)
for i in range(100):
exampleLabel = tk.Label(exampleFrame, text = f"I'm in the scrolled frame! ({i})")
exampleLabel.pack(fill="x")
root.mainloop()
感謝@Novel 幫助回答了這個問題。
可以通過向 class 添加__getattr__
方法來實現所需的行為。 如果 class 從tk.Frame
繼承,這將不起作用,因此已將其刪除。 這是代碼:
class scrolledFrame():
def __init__(self, parent):
self.wrapper = tk.Frame(parent)
self.canvas = tk.Canvas(self.wrapper)
self.canvas.pack(fill = "both", expand = True, side = "left")
self.scroll = tk.Scrollbar(self.wrapper, command = self.canvas.yview)
self.scroll.pack(side = "right", fill = "y")
self.canvas.config(yscrollcommand = self.scroll.set)
self.content = tk.Frame(self.canvas)
self.content.bind("<Configure>", self.resizeCanvas)
self.contentWindow = self.canvas.create_window((0,0), window = self.content, anchor = "nw")
self.content.bind("<Enter>", self.enableScrollCanvas)
self.content.bind("<Leave>", self.disableScrollCanvas)
self.attrib = set(dir(tk.Widget))
def __getattr__(self, item):
if item in self.attrib:
return getattr(self.wrapper, item)
else:
return getattr(self.content, item)
def __str__(self):
return str(self.wrapper)
def scrollCanvas(self, event):
self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
def enableScrollCanvas(self, event):
self.canvas.bind_all("<MouseWheel>", self.scrollCanvas)
def disableScrollCanvas(self, event):
self.canvas.unbind_all("<MouseWheel>")
def resizeCanvas(self, event):
self.update_idletasks()
self.canvas.config(scrollregion = self.canvas.bbox("all"))
self.canvas.itemconfig(self.contentWindow, width = self.canvas.winfo_width())
root = tk.Tk()
exampleFrame = scrolledFrame(root)
exampleFrame.pack()
exampleLabel = tk.Label(exampleFrame, text = "I'm in the scrolled frame!")
exampleLabel.pack()
root.mainloop()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.