Python Forum
[Tkinter] canvas widget scroll issue - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [Tkinter] canvas widget scroll issue (/thread-33148.html)



canvas widget scroll issue - chrisdb - Apr-02-2021

Hi,

I have a canvas inside a frame that contains 3 entry widgets, but for some reason ,when I scroll up, the widgets move down, althoug there is no space above these entries.

Below is my code:
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master: tk.Tk = None):
        super().__init__(master)
        self.master = master
        self.grid(row=0)
        self.create_widgets()

    def create_widgets(self):
        # Table view with entries in scrollable frame
        self.scroll_frame = ScrollableFrame(self.master)
        self.scroll_frame.grid(row=4, column=0,  columnspan = 5, padx = (10, 10), sticky="W")
        
        tab_entry = tk.Entry(self.scroll_frame.scrollable_frame, relief=tk.GROOVE, width = 191)
        tab_entry.grid(row=1, column=0, sticky=tk.NSEW)
        tab_entry1 = tk.Entry(self.scroll_frame.scrollable_frame, relief=tk.GROOVE, width = 191)
        tab_entry1.grid(row=2, column=0, sticky=tk.NSEW)
        tab_entry2 = tk.Entry(self.scroll_frame.scrollable_frame, relief=tk.GROOVE, width = 191)
        tab_entry2.grid(row=3, column=0, sticky=tk.NSEW)

class ScrollableFrame(tk.Frame):
    """ Create a scrollable frame for use with 'Entry' widgets in table form
        
    Attributes:
        canvas (tkinter.Canvas)
        scrollable_frame (tkinter.Frame): frame for use inside canvas to enable scrolling of widgets
    """
    def __init__(self, container: tk.Tk, *args, **kwargs):
        super().__init__(container, *args, **kwargs)

        self.canvas = tk.Canvas(self, scrollregion=(0, 0, 1150, 180), width = 1150, height = 180, bg='white' )

        scrollbar_y = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
        scrollbar_x = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
        
        # reset the view
        self.canvas.xview_moveto(0)
        self.canvas.yview_moveto(0)

        self.scrollable_frame = tk.Frame(self.canvas)

        self.scrollable_frame.bind(
            "<Configure>",
            lambda e: self.canvas.configure(
                scrollregion = self.canvas.bbox("all")
            )
        )

        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")

        self.canvas.configure(yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set)
        
        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)

        self.canvas.grid(row=0, column=0, sticky="news")
        scrollbar_y.grid(row=0, column=1, sticky='ns')
        scrollbar_x.grid(row=1, column=0, sticky='ew')
        
        
        
    def _on_mousewheel(self, event: tk.Event):
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")

        
if __name__ == '__main__':
    root = tk.Tk()
    root.title("test")
    root.geometry('{}x{}+{}+{}'.format(1200, 620, 40, 40))
    root.resizable(0,0)
    app = Application(master=root)
    app.mainloop()
Is there a reason why this strange scroll issue occurs?
I'm running this on Windows with Python 3.9.

Thank you


RE: canvas widget scroll issue - deanhystad - Apr-04-2021

I'm guessing you mean that things move when you spin the mouse wheel. The reason this happens is because your code includes this:
    def _on_mousewheel(self, event: tk.Event):
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
If you tell the canvas to scroll, shouldn't it scroll?

A scrollbar is smart. It knows when to enable/disable the thumb, resize the thumb, position the thumb. It knows what to do when the scroll window is smaller or larger than the view window. Your event code is not smart. You spin the mouse wheel and it scrolls. If you want the mouse wheel to be smart, maybe it should work through the scrollbar.


RE: canvas widget scroll issue - chrisdb - Apr-07-2021

(Apr-04-2021, 10:42 PM)deanhystad Wrote: I'm guessing you mean that things move when you spin the mouse wheel. The reason this happens is because your code includes this:
    def _on_mousewheel(self, event: tk.Event):
        self.canvas.yview_scroll(int(-1*(event.delta/120)), "units")
If you tell the canvas to scroll, shouldn't it scroll?

A scrollbar is smart. It knows when to enable/disable the thumb, resize the thumb, position the thumb. It knows what to do when the scroll window is smaller or larger than the view window. Your event code is not smart. You spin the mouse wheel and it scrolls. If you want the mouse wheel to be smart, maybe it should work through the scrollbar.

Thx for the info, but what I don't understand then is when I enter widgets that span beyond the scroll view, the scrolling does in fact work correctly...