代码之家  ›  专栏  ›  技术社区  ›  BobC

一起滚动多个tkinter列表框

  •  8
  • BobC  · 技术社区  · 14 年前

    我有多个tkinter列表框,我使用一个滚动条滚动在一起,但我也希望它们一起滚动,以便在任何列表框上进行鼠标跟踪活动。

    怎么做?

    我当前的代码基于这里讨论的最后一个模式: http://effbot.org/tkinterbook/listbox.htm 当只使用滚动条时,它工作得很好,但是当使用mousewheel时,列表框会独立滚动。

    3 回复  |  直到 8 年前
        1
  •  10
  •   Bryan Oakley    14 年前

    解决这个问题的方法与将两个小部件连接到单个滚动条的方法几乎相同:为mousewheel创建自定义绑定,并让这些绑定影响两个列表框,而不仅仅是一个列表框。

    唯一真正的诀窍是知道根据平台的不同,鼠标跟会有不同的事件:Windows和Mac会 <MouseWheel> 事件,Linux获取 <Button-4> <Button-5> 事件。

    下面是一个在我的Mac上用python 2.5测试的例子:

    import Tkinter as tk
    
    class App:
        def __init__(self):
            self.root=tk.Tk()
            self.vsb = tk.Scrollbar(orient="vertical", command=self.OnVsb)
            self.lb1 = tk.Listbox(self.root, yscrollcommand=self.vsb.set)
            self.lb2 = tk.Listbox(self.root, yscrollcommand=self.vsb.set)
            self.vsb.pack(side="right",fill="y")
            self.lb1.pack(side="left",fill="x", expand=True)
            self.lb2.pack(side="left",fill="x", expand=True)
            self.lb1.bind("<MouseWheel>", self.OnMouseWheel)
            self.lb2.bind("<MouseWheel>", self.OnMouseWheel)
            for i in range(100):
                self.lb1.insert("end","item %s" % i)
                self.lb2.insert("end","item %s" % i)
            self.root.mainloop()
    
        def OnVsb(self, *args):
            self.lb1.yview(*args)
            self.lb2.yview(*args)
    
        def OnMouseWheel(self, event):
            self.lb1.yview("scroll", event.delta,"units")
            self.lb2.yview("scroll",event.delta,"units")
            # this prevents default bindings from firing, which
            # would end up scrolling the widget twice
            return "break"
    
    app=App()
    
        2
  •  10
  •   nbro kai    8 年前

    我知道这很古老,但我认为这个解决方案比这里的那些专业人士要简单一点。假设你 总是

    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()
    
        3
  •  1
  •   BobC    14 年前

    def showLists(l, *lists):
        """
        Present passed equal-length lists in adjacent scrollboxes.
        """
        # This exists mainly for me to start learning about Tkinter.
        # This widget reqires at least one list be passed, and as many additional
        # lists as desired.  Each list is displayed in its own listbox, with
        # additional listboxes added to the right as needed to display all lists.
        # The width of each listbox is set to match the max width of its contents.
        # Caveat: Too wide or too many lists, and the widget can be wider than the screen!
        # The listboxes scroll together, using either the scrollbar or mousewheel.
    
        # :TODO: Refactor as an object with methods.
        # :TODO: Move to a separate file when other widgets are built.
    
        # Check arguments
        if (l is None) or (len(l) < 1):
            return
        listOfLists = [l]     # Form a list of lists for subsequent processing
        listBoxes = []  # List of listboxes
        if len(lists) > 0:
            for list in lists:
                # All lists must match length of first list
                # :TODO: Add tail filling for short lists, with error for long lists
                if len(list) != len(l):
                    return
                listOfLists.append(list)
    
        import Tkinter
    
        def onVsb(*args):
            """
            When the scrollbar moves, scroll the listboxes.
            """
            for lb in listBoxes:
                lb.yview(*args)
    
        def onMouseWheel(event):
            """
            Convert mousewheel motion to scrollbar motion.
            """
            if (event.num == 4):    # Linux encodes wheel as 'buttons' 4 and 5
                delta = -1
            elif (event.num == 5):
                delta = 1
            else:                   # Windows & OSX
                delta = event.delta
            for lb in listBoxes:
                lb.yview("scroll", delta, "units")
            # Return 'break' to prevent the default bindings from
            # firing, which would end up scrolling the widget twice.
            return "break"
    
        # Create root window and scrollbar
        root = Tkinter.Tk()
        root.title('Samples w/ time step < 0')
        vsb = Tkinter.Scrollbar(root, orient=Tkinter.VERTICAL, command=onVsb)
        vsb.pack(side=Tkinter.RIGHT, fill=Tkinter.Y)
    
        # Create listboxes
        for i in xrange(0,len(listOfLists)):
            lb = Tkinter.Listbox(root, yscrollcommand=vsb.set)
            lb.pack(side=Tkinter.LEFT, fill=Tkinter.BOTH)
            # Bind wheel events on both Windows/OSX & Linux;
            lb.bind("<MouseWheel>", onMouseWheel)
            lb.bind("<Button-4>", onMouseWheel)
            lb.bind("<Button-5>", onMouseWheel)
            # Fill the listbox
            maxWidth = 0
            for item in listOfLists[i]:
                s = str(item)
                if len(s) > maxWidth:
                    maxWidth = len(s)
                lb.insert(Tkinter.END, s)
            lb.config(width=maxWidth+1)
            listBoxes.append(lb)        # Add listbox to list of listboxes
    
        # Show the widget
        Tkinter.mainloop()
    # End of showLists()