Scrolling multiple Tkinter listboxes together

BobC picture BobC · Nov 1, 2010 · Viewed 14.7k times · Source

I have multiple Tkinter listboxes that I have scrolling together using a single scrollbar, but I'd ALSO like them to scroll together for mousewheel activity over any of the listboxes.

How to do this?

My current code is based on the last pattern discussed here: http://effbot.org/tkinterbook/listbox.htm It works fine when using only the scrollbar, but the listboxes scroll independently when the mousewheel is used.

Answer

Santiclause picture Santiclause · Jul 5, 2012

I know this is pretty old, but I think the solution is a bit more simple than those proferred here. Assuming that you always want the listboxes to be in agreement, then the above two answers aren't even complete solutions - changing selection by means of the arrow keys will scroll one listbox but not the other.

So, looking at the answers, I asked - why aren't they hooking the yscrollcommand callback instead of just sending it straight to the scrollbar? So, I did just that:

try:
    from Tkinter import *
except ImportError:
    from tkinter import *


class MultipleScrollingListbox(Tk):

    def __init__(self):
        Tk.__init__(self)
        self.title('Scrolling Multiple Listboxes')

        #the shared scrollbar
        self.scrollbar = Scrollbar(self, orient='vertical')

        #note that yscrollcommand is set to a custom method for each listbox
        self.list1 = Listbox(self, yscrollcommand=self.yscroll1)
        self.list1.pack(fill='y', side='left')

        self.list2 = Listbox(self, yscrollcommand=self.yscroll2)
        self.list2.pack(expand=1, fill='both', side='left')

        self.scrollbar.config(command=self.yview)
        self.scrollbar.pack(side='right', fill='y')

        #fill the listboxes with stuff
        for x in xrange(30):
            self.list1.insert('end', x)
            self.list2.insert('end', x)

    #I'm sure there's probably a slightly cleaner way to do it than this
    #Nevertheless - whenever one listbox updates its vertical position,
    #the method checks to make sure that the other one gets updated as well.
    #Without the check, I *think* it might recurse infinitely.
    #Never tested, though.
    def yscroll1(self, *args):
        if self.list2.yview() != self.list1.yview():
            self.list2.yview_moveto(args[0])
        self.scrollbar.set(*args)

    def yscroll2(self, *args):
        if self.list1.yview() != self.list2.yview():
            self.list1.yview_moveto(args[0])
        self.scrollbar.set(*args)

    def yview(self, *args):
        self.list1.yview(*args)
        self.list2.yview(*args)


if __name__ == "__main__":
    root = MultipleScrollingListbox()
    root.mainloop()