11

I have a ttk Combobox I'd like to unbind from the mousewheel so that scrolling with the wheel while the Combobox is active doesn't change the value (instead it scrolls the frame).

I've tried unbind as well as binding to and empty function but neither works. See below:

import Tkinter as tk
import ttk


class app(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        self.interior = tk.Frame(self)

        tkvar = tk.IntVar()
        combo = ttk.Combobox(self.interior,
                             textvariable = tkvar,
                             width = 10,
                             values =[1, 2, 3])
        combo.unbind("<MouseWheel>")
        combo.bind("<MouseWheel>", self.empty_scroll_command)
        combo.pack()
        self.interior.pack()


    def empty_scroll_command(self, event):
        return

sample = app()
sample.mainloop()

Any help would be greatly appreciated.

Thanks!

Andrew Brown
  • 350
  • 1
  • 12
  • Show us a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). Also, what OS are you using? – Novel May 30 '17 at 17:59
  • Updated example with a class that can be used to test. Using 2.7 on Windows. – Andrew Brown May 30 '17 at 18:09
  • 1
    Your example is not complete and does not demonstrate your problem. – Novel May 30 '17 at 18:15
  • Sorry - forgot to pack them. Notice that there isn't any problem with this per se. My question is how I configure the combobox such that after selecting an option, using the mouse scrollwheel does not change the selection... In my application combo is placed in a scrolled frame (not included here to maintain the MINIMAL requirement) and I want the scrollwheel to control only the frame and not change the selection. Thanks for the help. – Andrew Brown May 30 '17 at 18:21
  • I can directly answer your question: bind the mousewheel as you have it and use `return "break"` to stop the escalation. I suspect that this will not solve your bigger issue and I can't help you with that unless you provide a complete example. – Novel May 30 '17 at 18:27

1 Answers1

15

The default binding is on the internal widget class, which gets executed after any custom bindings that you add. You can remove that default binding which will affect your whole app, or you can bind a specific widget to a custom function that returns the string "break" which will prevent the default binding from being run.

Remove the class binding

The internal class of the ttk combobox is TCombobox. You can pass that to unbind_class:

# Windows & OSX
combo.unbind_class("TCombobox", "<MouseWheel>")

# Linux and other *nix systems:
combo.unbind_class("TCombobox", "<ButtonPress-4>")
combo.unbind_class("TCombobox", "<ButtonPress-5>")

Adding a custom binding

When a binding on an individual returns the string "break" which will prevent default bindings from being processed.

# Windows and OSX
combo.bind("<MouseWheel>", self.empty_scroll_command)

# Linux and other *nix systems
combo.bind("<ButtonPress-4>", self.empty_scroll_command)
combo.bind("<ButtonPress-5>", self.empty_scroll_command)

def empty_scroll_command(self, event):
    return "break"
Saad
  • 3,340
  • 2
  • 10
  • 32
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • 1
    Both of these work perfectly. I chose to remove the class binding so that the scrolling function of the frame was maintained. Thanks for the help and clear examples! – Andrew Brown May 30 '17 at 18:35
  • 1
    @AndrewBrown: removing the class binding shouldn't affect anything other than the other comboboxes. It won't affect the scrolling of the frame or any other widgets. – Bryan Oakley May 30 '17 at 18:41
  • 1
    for some reason using the custom binding option was not scrolling while the combobox was still in focus (highlighted). I used a vertical scrolled canvas with a root - bind_all command for scrolling. Likely it's something in my setup... not too concerned since I have a workable option but let me know if you have any ideas. Thanks again! – Andrew Brown May 30 '17 at 19:01