복붙노트

[PYTHON] 여러 개의 Tkinter 목록 상자를 함께 스크롤하기

PYTHON

여러 개의 Tkinter 목록 상자를 함께 스크롤하기

하나의 스크롤바를 사용하여 여러 개의 Tkinter 목록 상자를 스크롤 할 수 있지만 목록 상자에서 마우스 휠 활동을 함께 스크롤 할 수 있습니다.

이 작업을 수행하는 방법?

현재 코드는 여기에 설명 된 마지막 패턴을 기반으로합니다 : http://effbot.org/tkinterbook/listbox.htm 스크롤바 만 사용하면 잘 작동하지만 마우스 휠을 사용하면 목록 상자가 독립적으로 스크롤됩니다.

해결법

  1. ==============================

    1.두 개의 위젯을 단일 스크롤 막대에 연결 한 것과 같은 방식으로 문제를 해결하십시오. 마우스 휠에 대한 사용자 정의 바인딩을 생성하고 이러한 바인딩이 단지 하나가 아닌 두 개의 목록 상자 모두에 영향을 주도록하십시오.

    두 개의 위젯을 단일 스크롤 막대에 연결 한 것과 같은 방식으로 문제를 해결하십시오. 마우스 휠에 대한 사용자 정의 바인딩을 생성하고 이러한 바인딩이 단지 하나가 아닌 두 개의 목록 상자 모두에 영향을 주도록하십시오.

    유일한 실제 트릭은 플랫폼에 따라 마우스 휠에 대한 다른 이벤트를 얻는 것입니다. Windows 및 Mac은 이벤트를 가져오고, Linux는 이벤트를 가져옵니다.

    필자의 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. ==============================

    2.나는 이것이 꽤 오래되었다는 것을 알고 있지만, 해결책은 여기에있는 것들보다 조금 더 간단하다고 생각합니다. 목록 상자를 항상 일치시키기를 원한다면 위의 두 가지 대답은 완전한 해결책이 아닙니다. 화살표 키로 선택을 변경하면 하나의 목록 상자가 스크롤되지만 다른 목록 상자는 스크롤되지 않습니다.

    나는 이것이 꽤 오래되었다는 것을 알고 있지만, 해결책은 여기에있는 것들보다 조금 더 간단하다고 생각합니다. 목록 상자를 항상 일치시키기를 원한다면 위의 두 가지 대답은 완전한 해결책이 아닙니다. 화살표 키로 선택을 변경하면 하나의 목록 상자가 스크롤되지만 다른 목록 상자는 스크롤되지 않습니다.

    그래서 응답을 살펴보면서 나는 스크롤바에 곧바로 보내는 대신 yscrollcommand 콜백을 연결하지 않는 이유를 묻습니다. 그래서, 나는 단지 그것을했다 :

    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. ==============================

    3.여기에 현재 솔루션이 있습니다. 독립형 함수로 코딩되었습니다 (예, 객체 여야합니다).

    여기에 현재 솔루션이 있습니다. 독립형 함수로 코딩되었습니다 (예, 객체 여야합니다).

    특징 / 요구 사항 :

    암호:

    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()
    

    개선을위한 제안은 환영합니다!

  4. from https://stackoverflow.com/questions/4066974/scrolling-multiple-tkinter-listboxes-together by cc-by-sa and MIT license