Python Forum
[Tkinter] canvas widget scroll issue
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] canvas widget scroll issue
#1
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
Reply
#2
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.
Reply
#3
(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...
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyQt] QTableView: scroll to top cell of the screen random_nick 2 2,765 Oct-08-2022, 12:29 AM
Last Post: random_nick
  [PyQt] How do I get a QScrollArea to scroll? LavaCreeperKing 9 7,599 Oct-29-2021, 08:33 AM
Last Post: Axel_Erfurt
  Treeview scroll selected node to top rfresh737 1 2,668 Apr-14-2021, 03:27 AM
Last Post: deanhystad
  Entry Widget issue PA3040 16 6,655 Jan-20-2021, 02:21 PM
Last Post: pitterbrayn
  [Tkinter] Help with scroll bars kraco 1 2,205 Sep-27-2020, 11:20 PM
Last Post: Larz60+
  How to place global tk text widget in class or on canvas puje 1 2,282 Jul-04-2020, 09:25 AM
Last Post: deanhystad
  Matplotlib figsize and centering issue on canvas deffonotsean 0 1,800 Jun-10-2020, 10:31 AM
Last Post: deffonotsean
  [Tkinter] How to place scroll bar correctly scratchmyhead 1 3,896 May-18-2020, 04:17 PM
Last Post: scratchmyhead
  Scroll frame with MouseWheel Nemesis 1 3,556 Mar-25-2020, 09:29 PM
Last Post: Nemesis
  The coordinates of the Entry widget (canvas) when moving berckut72 8 5,848 Jan-07-2020, 09:26 AM
Last Post: berckut72

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020