簡體   English   中英

tkinter 中的可滾動框架 class

[英]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的實例上調用packplacegrid時,它會做錯事,因為實例指向內部框架而不是外部框架。

詭計如下:解決方案是將對packplacegrid的調用重定向到外框。

class scrolledFrame(tk.Frame):
    def __init__(self, parent):
        ...
        self.pack = self.outer.pack
        self.place = self.outer.place
        self.grid = self.outer.grid

這樣,您就可以隨意使用scrolledFrame ,只要在將其添加到布局時使用packplacegrid

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM