I'm trying to make a canvas scrollable with a mousewheel. I tried this to see if I could at least print something with the action of the mousewheel:
from tkinter import *
from tkinter import ttk
import platform
class MainWindow:
def __init__(self):
self.metrics = []
self.content = ttk.Frame(root)
self.content.grid_rowconfigure(0, weight = 1)
self.content.grid_columnconfigure(0, weight = 1)
self.scrollable_canvas = Canvas(self.content)
self.vscrollbar = ttk.Scrollbar(self.content, orient = VERTICAL, command = self.scrollable_canvas.yview)
self.hscrollbar = ttk.Scrollbar(self.content, orient = HORIZONTAL, command = self.scrollable_canvas.xview)
self.scrollable_canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand = self.hscrollbar.set)
self.scrollable_canvas.bind('<Configure>',
lambda e: self.scrollable_canvas.configure(scrollregion = self.scrollable_canvas.bbox("all")))
self.inner_frame = Frame(self.scrollable_canvas)
self.scrollable_canvas.create_window((0, 0), window = self.inner_frame, anchor = "nw", width = 1000)
self.scrollable_canvas.xview_moveto(0)
self.scrollable_canvas.yview_moveto(0)
self.class_label = Label(self.inner_frame, text = "labels")
self.A_label = Label(self.inner_frame, text = "A")
self.A_entry = Entry(self.inner_frame, width = 5)
self.A_input = self.A_entry.get()
self.A_hint = Label(self.inner_frame, text = "A")
self.B_label = Label(self.inner_frame, text = "B")
self.B_entry = Entry(self.inner_frame, width = 5)
self.B_input = self.B_entry.get()
self.B_hint = Label(self.inner_frame, text = "B")
self.C = Label(self.inner_frame, text = "C")
self.space = Label(self.inner_frame, text = "")
self.D_label = Label(self.inner_frame, text = "D")
self.D_entry = Entry(self.inner_frame, width = 5)
self.D_hint = Label(self.inner_frame, text = "D")
self.E_label = Label(self.inner_frame, text = "E")
self.E_entry = Entry(self.inner_frame, width = 5)
self.E_hint = Label(self.inner_frame, text = "D")
self.F_label = Label(self.inner_frame, text = "F")
self.F_entry = Entry(self.inner_frame, width = 5)
self.F_hint = Label(self.inner_frame, text = "F")
self.G_label = Label(self.inner_frame, text = "G")
self.G_entry = Entry(self.inner_frame, width = 5)
self.G_hint = Label(self.inner_frame, text = "G")
self.H_label = Label(self.inner_frame, text = "H")
self.H_entry = Entry(self.inner_frame, width = 5)
self.H_hint = Label(self.inner_frame, text = "H")
self.I_label = Label(self.inner_frame, text = "I")
self.I_entry = Entry(self.inner_frame, width = 5)
self.I_hint = Label(self.inner_frame, text = "I")
self.J_label = Label(self.inner_frame, text = "J")
self.J_entry = Entry(self.inner_frame, width = 5)
self.J_hint = Label(self.inner_frame, text = "J")
self.K_label = Label(self.inner_frame, text = "K")
self.K_entry = Entry(self.inner_frame, width = 5)
self.K_hint = Label(self.inner_frame, text = "K")
self.space2 = Label(self.inner_frame, text = "")
self.L_label = Label(self.inner_frame, text = "L")
self.L_entry = Entry(self.inner_frame, width = 5)
self.content.pack(fill = BOTH, expand = 1)
self.scrollable_canvas.grid(row = 0, column = 0, sticky = "nsew")
self.vscrollbar.grid(row = 0, column = 1, sticky = "ns")
self.hscrollbar.grid(row = 1, column = 0, sticky = "ew")
self.class_label.grid(row = 0, column = 0)
self.A_label.grid(row = 1, column = 0)
self.A_entry.grid(row = 1, column = 1)
self.A_hint.grid(row = 1, column = 3, sticky = "w")
self.B_label.grid(row = 2, column = 0)
self.B_entry.grid(row = 2, column = 1)
self.B_hint.grid(row = 2, column = 3, sticky = "w")
self.C.grid(row = 3, column = 3, sticky = "w")
self.space.grid(row = 4, column = 0)
self.D_label.grid(row = 6, column = 0)
self.D_entry.grid(row = 6, column = 1)
self.D_hint.grid(row = 6, column = 3, sticky = "w")
self.E_label.grid(row = 7, column = 0)
self.E_entry.grid(row = 7, column = 1)
self.E_hint.grid(row = 7, column = 3, sticky = "w")
self.F_label.grid(row = 8, column = 0)
self.F_entry.grid(row = 8, column = 1)
self.F_hint.grid(row = 8, column = 3, sticky = "w")
self.G_label.grid(row = 9, column = 0)
self.G_entry.grid(row = 9, column = 1)
self.G_hint.grid(row = 9, column = 3, sticky = "w")
self.H_label.grid(row = 10, column = 0)
self.H_entry.grid(row = 10, column = 1)
self.H_hint.grid(row = 10, column = 3, sticky = "w", columnspan = 2)
self.I_label.grid(row = 11, column = 0)
self.I_entry.grid(row = 11, column = 1)
self.I_hint.grid(row = 11, column = 3, sticky = "w", columnspan = 2)
self.J_label.grid(row = 12, column = 0)
self.J_entry.grid(row = 12, column = 1)
self.J_hint.grid(row = 12, column = 3, sticky = "w", columnspan = 2)
self.K_label.grid(row = 13, column = 0)
self.K_entry.grid(row = 13, column = 1)
self.K_hint.grid(row = 13, column = 3, sticky = "w", columnspan = 2)
self.space2.grid(row = 14, column = 0)
self.L_label.grid(row = 19, column = 0)
self.L_entry.grid(row = 19, column = 1)
root.mainloop()
def mouse_wheel(event):
print("test mouse wheel event")
global count
if event.num == 5 or event.delta < 0:
count -= 1
if event.num == 4 or event.delta > 0:
count = 1
print(count)
if __name__ == '__main__':
root = Tk()
count = 0
if platform.system() == "Windows":
print("line 276")
root.bind("<MouseWheel>", mouse_wheel)
print("line 278")
else:
print("line 280")
root.bind("<Button-4>", mouse_wheel)
print("line 282")
root.bind("<Button-5>", mouse_wheel)
print("line 284")
root.title("title")
new_window = MainWindow()
However, the function mouse_weel
is never called. How come I get "line 280", "line 282" and "line 284" but not "test mouse wheel event".
I can get the mouse wheel to work with a non-OO program.
I found this solution but couldn't adapt it to my problem.
CodePudding user response:
Here is the solution I found:
from tkinter import *
from tkinter import ttk
import platform
class MainWindow:
def __init__(self):
self.metrics = []
self.content = ttk.Frame(root)
self.content.grid_rowconfigure(0, weight = 1)
self.content.grid_columnconfigure(0, weight = 1)
self.scrollable_canvas = Canvas(self.content)
self.vscrollbar = ttk.Scrollbar(self.content, orient = VERTICAL, command = self.scrollable_canvas.yview)
self.hscrollbar = ttk.Scrollbar(self.content, orient = HORIZONTAL, command = self.scrollable_canvas.xview)
self.scrollable_canvas.configure(yscrollcommand=self.vscrollbar.set, xscrollcommand = self.hscrollbar.set)
self.scrollable_canvas.bind('<Configure>',
lambda e: self.scrollable_canvas.configure(scrollregion = self.scrollable_canvas.bbox("all")))
self.inner_frame = Frame(self.scrollable_canvas)
self.scrollable_canvas.create_window((0, 0), window = self.inner_frame, anchor = "nw", width = 1000)
self.scrollable_canvas.xview_moveto(0)
self.scrollable_canvas.yview_moveto(0)
if platform.system() == "Linux":
self.inner_frame.bind("<Button-4>", self.mouse_wheel)
self.inner_frame.bind("<Button-5>", self.mouse_wheel)
else:
self.inner_frame.bind("<MouseWheel>", self.mouse_wheel)
self.class_label = Label(self.inner_frame, text = "labels")
self.A_label = Label(self.inner_frame, text = "A")
self.A_entry = Entry(self.inner_frame, width = 5)
self.A_input = self.A_entry.get()
self.A_hint = Label(self.inner_frame, text = "A")
self.B_label = Label(self.inner_frame, text = "B")
self.B_entry = Entry(self.inner_frame, width = 5)
self.B_input = self.B_entry.get()
self.B_hint = Label(self.inner_frame, text = "B")
self.C = Label(self.inner_frame, text = "C")
self.space = Label(self.inner_frame, text = "")
self.D_label = Label(self.inner_frame, text = "D")
self.D_entry = Entry(self.inner_frame, width = 5)
self.D_hint = Label(self.inner_frame, text = "D")
self.E_label = Label(self.inner_frame, text = "E")
self.E_entry = Entry(self.inner_frame, width = 5)
self.E_hint = Label(self.inner_frame, text = "D")
self.F_label = Label(self.inner_frame, text = "F")
self.F_entry = Entry(self.inner_frame, width = 5)
self.F_hint = Label(self.inner_frame, text = "F")
self.G_label = Label(self.inner_frame, text = "G")
self.G_entry = Entry(self.inner_frame, width = 5)
self.G_hint = Label(self.inner_frame, text = "G")
self.H_label = Label(self.inner_frame, text = "H")
self.H_entry = Entry(self.inner_frame, width = 5)
self.H_hint = Label(self.inner_frame, text = "H")
self.I_label = Label(self.inner_frame, text = "I")
self.I_entry = Entry(self.inner_frame, width = 5)
self.I_hint = Label(self.inner_frame, text = "I")
self.J_label = Label(self.inner_frame, text = "J")
self.J_entry = Entry(self.inner_frame, width = 5)
self.J_hint = Label(self.inner_frame, text = "J")
self.K_label = Label(self.inner_frame, text = "K")
self.K_entry = Entry(self.inner_frame, width = 5)
self.K_hint = Label(self.inner_frame, text = "K")
self.space2 = Label(self.inner_frame, text = "")
self.L_label = Label(self.inner_frame, text = "L")
self.L_entry = Entry(self.inner_frame, width = 5)
self.content.pack(fill = BOTH, expand = 1)
self.scrollable_canvas.grid(row = 0, column = 0, sticky = "nsew")
self.vscrollbar.grid(row = 0, column = 1, sticky = "ns")
self.hscrollbar.grid(row = 1, column = 0, sticky = "ew")
self.class_label.grid(row = 0, column = 0)
self.A_label.grid(row = 1, column = 0)
self.A_entry.grid(row = 1, column = 1)
self.A_hint.grid(row = 1, column = 3, sticky = "w")
self.B_label.grid(row = 2, column = 0)
self.B_entry.grid(row = 2, column = 1)
self.B_hint.grid(row = 2, column = 3, sticky = "w")
self.C.grid(row = 3, column = 3, sticky = "w")
self.space.grid(row = 4, column = 0)
self.D_label.grid(row = 6, column = 0)
self.D_entry.grid(row = 6, column = 1)
self.D_hint.grid(row = 6, column = 3, sticky = "w")
self.E_label.grid(row = 7, column = 0)
self.E_entry.grid(row = 7, column = 1)
self.E_hint.grid(row = 7, column = 3, sticky = "w")
self.F_label.grid(row = 8, column = 0)
self.F_entry.grid(row = 8, column = 1)
self.F_hint.grid(row = 8, column = 3, sticky = "w")
self.G_label.grid(row = 9, column = 0)
self.G_entry.grid(row = 9, column = 1)
self.G_hint.grid(row = 9, column = 3, sticky = "w")
self.H_label.grid(row = 10, column = 0)
self.H_entry.grid(row = 10, column = 1)
self.H_hint.grid(row = 10, column = 3, sticky = "w", columnspan = 2)
self.I_label.grid(row = 11, column = 0)
self.I_entry.grid(row = 11, column = 1)
self.I_hint.grid(row = 11, column = 3, sticky = "w", columnspan = 2)
self.J_label.grid(row = 12, column = 0)
self.J_entry.grid(row = 12, column = 1)
self.J_hint.grid(row = 12, column = 3, sticky = "w", columnspan = 2)
self.K_label.grid(row = 13, column = 0)
self.K_entry.grid(row = 13, column = 1)
self.K_hint.grid(row = 13, column = 3, sticky = "w", columnspan = 2)
self.space2.grid(row = 14, column = 0)
self.L_label.grid(row = 19, column = 0)
self.L_entry.grid(row = 19, column = 1)
root.mainloop()
def mouse_wheel(self, event):
print(str(event.delta) " is event.delta")
print(str(event.state) " is event.state")
if event.state == 1:
self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
elif event.state == 0:
self.scrollable_canvas.yview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
if __name__ == '__main__':
root = Tk()
count = 0
global scrollable_malus
if platform.system() == "Windows":
scrollable_malus = 120
else:
scrollable_malus = 1
root.title("title")
new_window = MainWindow()
In mouse_wheel
, xview_scroll
and yview_scroll
were already used for the scrollbars. These commands can scroll by page or unit. In this case, I chose unit.
event.state
is 1
when scrolling horizontally and 0
when scrolling vertically. When scrolling up, event.delta
is positive but it is also positive when scrolling left so event.state
is required to know the direction.
On Windows, event.delta
is a multiple of 120 so I had to create a malus that would be worth 120 on Windows.
Depending on whether or not you want to invert the scrolling direction, you may want to delete the -1 multiplier.
I both cases of mouse_wheel
, I should have written:
if event.num == 5 or event.delta < 0:
self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
if event.num == 4 or event.delta > 0:
self.scrollable_canvas.xview_scroll(int(-1*(event.delta)/scrollable_malus), "units")
Since it is the same formula on both cases, I refactored it.
I left event.delta
and event.state
to show the scrolling direction so that other users can use it and understand why I did what I did.