简体   繁体   中英

Tkinter Mousewheel action for scrolling on canvas

I am new to python and I have an issue adding mouse scrolling action to my canvas.I have a vertical scrollbar.The scrollbar works fine when I manually scroll it, or mouse over it and roll my mousewheel. My issue is that I would like to be able roll my mousewheel on my canvas or even just my frame and have the contents inside it scroll as long as my mouse is hovering over it. I have spent hours looking at all the similar questions related to this here on stackoverflow, and none of my modifications seem to work. I am currently getting a weird error that I cannot rectify. Due to my modifications, the error ONLY shows up when I start scrolling, however it does not cause a crash.The error is:-

            Exception in Tkinter callback
            Traceback (most recent call last):
              File "C:\Users\twaku\Anaconda3\lib\tkinter\__init__.py", line 1699, in __call__
                return self.func(*args)
              File "C:/Users/twaku/PycharmProjects/DCSui/FileToSubmit.py", line 152, in _on_mousewheel
                self.canvas.yview_scroll(int(-1 * (event.delta / 120), "units"))
            TypeError: 'str' object cannot be interpreted as an integer

Now if I remove the "int" typecast I get this error:-

             Exception in Tkinter callback
            Traceback (most recent call last):
              File "C:\Users\twaku\Anaconda3\lib\tkinter\__init__.py", line 1699, in __call__
                return self.func(*args)
              File "C:/Users/twaku/PycharmProjects/DCSui/FileToSubmit.py", line 156, in _on_mousewheel
                self.canvas.yview_scroll(-1 * (event.delta / 120), "units")
              File "C:\Users\twaku\Anaconda3\lib\tkinter\__init__.py", line 1745, in yview_scroll
                self.tk.call(self._w, 'yview', 'scroll', number, what)
            _tkinter.TclError: expected integer but got "1.0"

So now I am stuck going back and forth between the two errors.

Here is my code :-

            from tkinter import *
            import tkinter as tk
            import time
            import xlrd


            root = Tk()


            root.state('zoomed')  # full screen -windowed

            # ------------------INTRODUCTION BLOCK--------------
            f1 = Frame(root, width=900, height=700, relief=SUNKEN)
            f1.grid_rowconfigure(1, weight=1)
            f1.grid_columnconfigure(2, weight=1)
            f1.pack(fill=BOTH, expand=1, side=BOTTOM)

            root.title("Diagram Scroll Test")

            Tops = Frame(root, width=1600, height=50, relief=SUNKEN)
            Tops.pack(side=TOP)

            # ------------------TIME--------------
            localtime = time.asctime(time.localtime(time.time()))
            # -----------------INFO TOP------------
            lblinfo = Label(Tops, font=('aria', 30, 'bold'), text="My Diagram Scroll Test",
                            fg="steel blue", bd=10, anchor='w')
            lblinfo.grid(row=0, column=0)
            lblinfo = Label(Tops, font=('aria', 20,), text=localtime, fg="steel blue", anchor=W)
            lblinfo.grid(row=1, column=0)
            lblinfo = Label(Tops, font=('aria', 15, 'bold'), text="Please help", fg="steel blue", bd=10,
                            anchor='w')
            lblinfo.grid(row=2, column=0)

            # ------------------CANVAS DEFINITION-------------

            class CanvasDemo(Frame):


                def __init__(self,root):
                    Frame.__init__(self,root)


                    self.canvas = tk.Canvas(root, borderwidth=0)
                    self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)
                    self.frame = tk.Frame(self.canvas)
                    self.vsb = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
                    self.canvas.configure(yscrollcommand=self.vsb.set)
                    root.state('zoomed')
                    self.vsb.pack(side="right", fill="y")
                    self.canvas.config(width=root.winfo_screenwidth(), height=root.winfo_screenheight())
                    # self.canvas.pack(side="left", fill="both", expand="1")
                    self.canvas.pack(fill="both", expand="1")
                    self.canvas.create_window((4, 4), window=self.frame, anchor="nw",
                                              tags="self.frame")

                    self.frame.bind("<Configure>", self.onFrameConfigure)

                    self.populate()

                # ------------------CODE TO CREATE BLOCK DIAGRAMS-------------

                def populate(self):


                    i = 0
                    turnCount = 0  # Keeps track of how many boxes is used to trigger a turn

                    # Create Small starter box
                    lineVarx1 = 70
                    lineVary1 = 50
                    lineVarx2 = 120
                    lineVary2 = 50

                    varx1 = 120
                    vary1 = 25
                    varx2 = 220
                    vary2 = 75

                    varblk = 1
                    varline = 1

                    self.canvas.create_rectangle(20, 40, 70, 60, fill="green", tags="start")



                    while i < 200:  # Provides 104 blocks

                        # ------------------IF STATEMENT TO CONTROL WHEN DIAGRAM TURNS-------------

                        if turnCount == 12:  # At Turn Point, initiating turn sequence
                            lineVarx2 = lineVarx2 - 25
                            self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")
                            # Downward line
                            lineVarx1 = lineVarx2
                            lineVary1 = lineVary2
                            lineVary2 = lineVary2 + 50
                            self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")

                            # long line to left
                            lineVarx1 = lineVarx2
                            lineVary1 = lineVary2
                            lineVarx2 = lineVarx2 - 1825
                            self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")

                            # Downward line
                            lineVarx1 = lineVarx2
                            lineVary1 = lineVary2
                            lineVary2 = lineVary2 + 50
                            self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")

                            lineVary1 = lineVary2
                            lineVarx2 = lineVarx2 + 50

                            varx1 = lineVarx2
                            vary1 = lineVary2 - 25
                            varx2 = lineVarx2 + 100
                            vary2 = lineVary2 + 25
                            turnCount = 0

                        self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")
                        self.canvas.create_rectangle(varx1, vary1, varx2, vary2, fill="bisque", tags="r1")
                        self.canvas.create_text(varx1 + 20, vary1, fill="darkblue", anchor=NW,
                                                text="Hi")
                        self.canvas.create_text(varx1 + 20, vary1 + 10, fill="darkblue", anchor=NW,
                                                text="bye")
                        self.canvas.create_text(varx1 + 20, vary1 + 20, fill="darkblue", anchor=NW,
                                                text="fly")
                        lineVarx1 = lineVarx1 + 150
                        lineVarx2 = lineVarx2 + 150
                        varx1 = varx1 + 150
                        varx2 = varx2 + 150
                        i += 1
                        turnCount += 1

                    # "End" Block
                    lineVarx1 = varx2 - 150
                    lineVarx2 = lineVarx1 + 50

                    varx1 = lineVarx2
                    vary1 = lineVary1 - 10
                    varx2 = varx1 + 50
                    vary2 = lineVary1 + 10

                    self.canvas.create_line(lineVarx1, lineVary1, lineVarx2, lineVary2, arrow="last", tags="to_r1")
                    self.canvas.create_rectangle(varx1, vary1, varx2, vary2, fill="red", tags="r1")






                def _on_mousewheel(self, event):
                        self.canvas.yview_scroll(-1 * (event.delta / 120), "units")



                def onFrameConfigure(self, event):
                    '''Reset the scroll region to encompass the inner frame'''
                    self.canvas.configure(scrollregion=self.canvas.bbox("all"))



            def qexit():
                root.destroy()


            btnexit = Button(f1, padx=16, pady=7, bd=10, fg="black", font=('ariel', 12, 'bold'), width=8, text="EXIT",
                             bg="powder blue", command=qexit)
            btnexit.grid(row=15, column=2)





            canvas = CanvasDemo(root)
            canvas.pack()

            mainloop()

When you divide the result is a float. Try with integer division instead:

def _on_mousewheel(self, event):
    self.canvas.yview_scroll(-1 * (event.delta // 120), "units")
                                        here:--^

Now, you may want to check which widget the mouse pointer is hovering above because the _on_mousewheel() function is invoked when the mouse pointer hovers on the scrollbar, making it scroll twice as fast.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM