简体   繁体   中英

Tkinter Binding Multiple Scrollbar's to MouseWheel

I'm building something that uses multiple scrollbars. This class is actually a wrapper for the tk.ScrollBar and it's used to create scrollable frames. What I want is to be able to set a "default" scroll-container.

Assume 90% of the time someone using the application would want to scroll some frame (Which we will call main_frame), and 10% of the time they would want to scroll a different frame. (normal_frame)

It would make sense to have the mousewheel scroll the normal_frame only when the user was hovering over it with the mouse, but to have the mousewheel scroll the main_frame in all instances except when hovering over normal_frame.

The problem is that whenever you call bind_all upon " <Enter> "(ing) the normal_frame, when you " <Leave> " it, the main_frame no longer scrolls. Any suggestions?

class ScrollThing(object):

    def __init__(self, some_frame, default=False):
        self.default = default
        self.canvas = tkinter.Canvas(some_frame)
        self.view_window = tkinter.Frame(self.canvas)
        #things and stuff to setup scroll bar


    def setup_view_window(self):
        if self.default:
            self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)
        else:
            self.view_window.bind('<Enter>', self.focus_in)
            self.view_window.bind('<Leave>', self.focus_out)

    def focus_in(self, *args):
        del args
        # I'm a seperate ScrollThing from main_frame
        # I don't have access to the other ScrollThing because
        # we are both dynamically created. 
        # I want to save the current bound arguments somehow
        # but .bindtags() returns only MY bindings

        self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)

    def focus_out(self, *args):
        self.canvas.unbind_all('<MouseWheel>', self.on_mousewheel

    def on_mousewheel(self, event):
        self.canvas.yview_scroll(int(-1*(event.delta//120)), 'units')

I just found a solution involving handing the function and the canvas back to the Master.

class Master(object)

    def __init__(self, *args, **kwargs):
        #Things and stuff
        self.default_scroll = None

Then by setting default_scroll to hold the default parameters

def setup_view_window(self):
    if self.default:
        self.canvas.bind_all('<MouseWheel>', self.on_mousewheel)

        # HERE
        self.dynamic.stuff.MASTER.default_scroll = [self.canvas, self.on_mousewheel]

    else:
        self.view_window.bind('<Enter>', self.focus_in)
        self.view_window.bind('<Leave>', self.focus_out)

You can then access it in the focus_out.

def focus_out(self, *args):
    self.canvas.unbind_all('<MouseWheel>', self.on_mousewheel)

    # HERE
    if self.dynamic.stuff.MASTER.default_scroll is not None:
        self.dynamic.stuff.MASTER.default_scroll[0].bind_all('<MouseWheel>', self.dynamic.stuff.MASTER.default_scroll[1])

Although, I would be interested to know if anyone knows of a way to access it in a more concise way, perhaps something in tkinter that lets you see all bound events in the entire application?

Arguably the simplest solution is to set a variable to be the widget you want to scroll, and then set a global binding to scroll that widget.

For example, your app would initialize the binding like this exactly once:

self.root.bind_all("<MouseWheel>", self.scroller)

Then, in scroller you scroll the default window:

def scroller(self, event):
    self.default_window.yview(...)

You can also add the binding to the canvases themselves instead of calling bind_all if you prefer. The basic concept still works without having to adjust the bindings on enter/leave events.

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