【问题标题】:Using mousewheel on scrollable frame在可滚动框架上使用鼠标滚轮
【发布时间】:2023-03-06 19:12:01
【问题描述】:

我使用此处提供的可滚动框架类在 tkinter 上工作: https://gist.github.com/mp035/9f2027c3ef9172264532fcd6262f3b01

这个类的实际代码是:

class ScrollFrame(ttk.Frame):
    def __init__(self, parent):
        super().__init__(parent) # create a frame (self)

        s=ttk.Style()
        s.configure('TFrame', background="#eff0f1")

        #place canvas on self
        self.canvas = tk.Canvas(self, borderwidth=0, background="#eff0f1", height = appHeight)
        #place a frame on the canvas, this frame will hold the child widgets
        self.viewPort = ttk.Frame(self.canvas, style='TFrame')
        #place a scrollbar on self
        self.vsb = ttk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        #attach scrollbar action to scroll of canvas
        self.canvas.configure(yscrollcommand=self.vsb.set)

        #pack scrollbar to right of self
        self.vsb.pack(side="right", fill="y")
        #pack canvas to left of self and expand to fil
        self.canvas.pack(side="left", fill="both", expand=True)
        self.canvas_window = self.canvas.create_window((4,4),
                                                 #add view port frame to canvas
                                                 window=self.viewPort, anchor="nw",
                                                 tags="self.viewPort")

        #bind an event whenever the size of the viewPort frame changes.
        self.viewPort.bind("<Configure>", self.onFrameConfigure)
        #bind an event whenever the size of the viewPort frame changes.
        self.canvas.bind("<Configure>", self.onCanvasConfigure)

        #perform an initial stretch on render, otherwise the scroll region has a tiny border until the first resize
        self.onFrameConfigure(None)

    def onFrameConfigure(self, event):
        '''Reset the scroll region to encompass the inner frame'''
        #whenever the size of the frame changes, alter the scroll region respectively.
        self.canvas.configure(scrollregion=self.canvas.bbox("all"))

    def onCanvasConfigure(self, event):
        '''Reset the canvas window to encompass inner frame when required'''
        canvas_width = event.width
        #whenever the size of the canvas changes alter the window region respectively.
        self.canvas.itemconfig(self.canvas_window, width = canvas_width)

它实际上工作得很好,除了我不能让鼠标滚轮在滚动条上工作......我必须点击滑块并让它滑动。每当我尝试使用鼠标滚轮滚动时,控制台中都会出现此错误:

Traceback (most recent call last):
  File "D:\Anaconda\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "D:\Anaconda\lib\tkinter\__init__.py", line 1739, in yview
    res = self.tk.call(self._w, 'yview', *args)
_tkinter.TclError: unknown option "": must be moveto or scroll

我发现了这个话题: tkinter: binding mousewheel to scrollbar

但为适应我的课程而给出的答案似乎都不起作用。

有谁知道如何调整我的可滚动框架以使鼠标滚轮工作? 提前致谢!!

【问题讨论】:

    标签: python tkinter mousewheel scrollable


    【解决方案1】:

    好的,我找到了答案,所以我在这里发布解决方案:

    init 的末尾,我添加了这个:

            self.viewPort.bind('<Enter>', self._bound_to_mousewheel)
            self.viewPort.bind('<Leave>', self._unbound_to_mousewheel)
    

    然后在我添加这个之后:

        def _bound_to_mousewheel(self, event):
            self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
    
        def _unbound_to_mousewheel(self, event):
            self.canvas.unbind_all("<MouseWheel>")
    
        def _on_mousewheel(self, event):
            self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
    

    我现在可以用鼠标滚轮在指针所在的地方滚动条!

    这里是完整的可滚动框架类代码:

    class ScrollFrame(ttk.Frame):
        def __init__(self, parent):
            super().__init__(parent) # create a frame (self)
    
            s=ttk.Style()
            s.configure('TFrame', background="#eff0f1")
    
            #place canvas on self
            self.canvas = tk.Canvas(self, borderwidth=0, background="#eff0f1", height = appHeight)
            #place a frame on the canvas, this frame will hold the child widgets
            self.viewPort = ttk.Frame(self.canvas, style='TFrame')
            #place a scrollbar on self
            self.vsb = ttk.Scrollbar(self, orient="vertical")
            #attach scrollbar action to scroll of canvas
            self.canvas.configure(yscrollcommand=self.vsb.set)
    
            #pack scrollbar to right of self
            self.vsb.pack(side="right", fill="y")
            #pack canvas to left of self and expand to fil
            self.canvas.pack(side="left", fill="both", expand=True)
            self.canvas_window = self.canvas.create_window((4,4),
                                                     #add view port frame to canvas
                                                     window=self.viewPort, anchor="nw",
                                                     tags="self.viewPort")
    
            #bind an event whenever the size of the viewPort frame changes.
            self.viewPort.bind("<Configure>", self.onFrameConfigure)
            #bind an event whenever the size of the viewPort frame changes.
            self.canvas.bind("<Configure>", self.onCanvasConfigure)
    
            #perform an initial stretch on render, otherwise the scroll region has a tiny border until the first resize
            self.onFrameConfigure(None)
    
            self.viewPort.bind('<Enter>', self._bound_to_mousewheel)
            self.viewPort.bind('<Leave>', self._unbound_to_mousewheel)
    
        def _bound_to_mousewheel(self, event):
            self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
    
        def _unbound_to_mousewheel(self, event):
            self.canvas.unbind_all("<MouseWheel>")
    
        def _on_mousewheel(self, event):
            self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
    
        def onFrameConfigure(self, event):
            '''Reset the scroll region to encompass the inner frame'''
            #whenever the size of the frame changes, alter the scroll region respectively.
            self.canvas.configure(scrollregion=self.canvas.bbox("all"))
    
        def onCanvasConfigure(self, event):
            '''Reset the canvas window to encompass inner frame when required'''
            canvas_width = event.width
            #whenever the size of the canvas changes alter the window region respectively.
            self.canvas.itemconfig(self.canvas_window, width = canvas_width)
    

    当你想在 tkinter 中创建一个页面时,你所要做的就是这样调用它:

    class NewPage(ttk.Frame):
        def __init__(self, parent, controller):
    
            ttk.Frame.__init__(self, parent)
    
            self.scrollFrame = ScrollFrame(self)
    

    如果您想在其中添加小部件,只需像这样使用“self.scrollFrame.viewPort”构建它们:

    label = ttk.Label(self.scrollFrame.viewPort, text = "Label", anchor = "center")
    

    希望对某人有所帮助;)

    【讨论】:

    • 顺便说一句,如果您在反引号后添加语言,那就太好了,所以在这种情况下,像这样:```python,然后像您一样在末尾添加 3 个反引号,我将进行编辑,以便您可以使用看看,它只是给语法着色,还有为什么__init__末尾有return None,没用,可以去掉
    • 哦,太好了,我不知道我能做到这一点!谢谢你,它确实更具可读性。哦,你适合return None。我想它仍然来自之前的尝试......我编辑了我的答案以删除它。也谢谢你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-15
    • 2021-05-18
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多