Python Forum

Full Version: canvas widget scroll issue
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
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
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.
(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...