I have a combobox within a scrollable canvas frame- when I open the combobox and attempt to scroll through the options, the combobox and the entire window both scroll together. It would be nice to pause canvas scrolling while the combobox is open, but unbinding the mousewheel scroll from the combobox would also work.
Here is the scrollable canvas code:
root = Tk()
width=800
height=1020
root.geometry(str(width) "x" str(height) " 10 10")
main_frame = Frame(root,width=width,height=height)
main_frame.place(x=0,y=0)
canvas = Canvas(main_frame, width=width, height=height)
canvas.place(x=0,y=0)
scrolly = ttk.Scrollbar(main_frame, orient=VERTICAL, command=canvas.yview)
scrolly.place(x=width-15,y=0,height=height)
canvas.configure(yscrollcommand=scrolly.set)
canvas.bind('<Configure>', lambda e: canvas.configure(scrollregion = canvas.bbox("all")))
def _on_mouse_wheel(event):
canvas.yview_scroll(-1 * int((event.delta / 120)), "units")
canvas.bind_all("<MouseWheel>", _on_mouse_wheel)
w = Frame(canvas,width=width,height=height)
w.place(x=0,y=0)
canvas.create_window((0,0), window=w, anchor="nw")
w.configure(height=3000)
Here is the combobox initialization:
sel = Combobox(w, values=data)
sel.place(x=xval, y=yval)
I have tried unbinding the mousewheel for the combobox
sel.unbind_class("TCombobox", "<MouseWheel>") # windows
as well as rebinding it to an empty function
def dontscroll(event):
return 'break'
sel.bind('<MouseWheel>', dontscroll)
but neither method worked.
I also attempted both methods in a separate test file (complete code):
from tkinter import *
from tkinter import ttk
from tkinter.ttk import Combobox
root = Tk()
root.geometry(str(300) "x" str(300) " 10 10")
def dontscroll(event):
return 'break'
sel = Combobox(root, values=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20])
sel.place(x=10, y=10)
sel.unbind_class("TCombobox", "<MouseWheel>") # on windows
sel.bind('<MouseWheel>', dontscroll)
This still didn't work. Any help is appreciated, thanks.
CodePudding user response:
The reason is that you are binding all "<MouseWheel>"
events with bind_all
, you can simple just change it to bind
, but then you will notice that it doesn't work with scrolls on the canvas, that is because you are now binding to canvas
but the scroll is actually(pretty counter intuitive) happening to w
which is a Frame
, so just bind to that widget instead:
w.bind("<MouseWheel>", _on_mouse_wheel)
And you can also remove all the unbind
and bind
related to sel
as it is no longer needed.
On an unrelated note, the trick I used to find out which widget triggered the "<MouseWheel>"
event could be useful in the future:
def _on_mouse_wheel(event):
print(event.widget) # Print the widget that triggered the event
canvas.yview_scroll(-1 * int((event.delta / 120)), "units")