簡體   English   中英

一起滾動多個 Tkinter 列表框

[英]Scrolling multiple Tkinter listboxes together

我有多個 Tkinter 列表框,我使用單個滾動條一起滾動,但我也希望它們一起滾動以在任何列表框上進行鼠標滾輪活動。

如何做到這一點?

我當前的代碼基於這里討論的最后一個模式: http : //effbot.org/tkinterbook/listbox.htm它在僅使用滾動條時工作正常,但在使用鼠標滾輪時列表框獨立滾動。

我知道這已經很老了,但我認為解決方案比這里提供的要簡單一些。 假設您總是希望列表框一致,那么以上兩個答案甚至都不是完整的解決方案 - 通過箭頭鍵更改選擇將滾動一個列表框而不是另一個。

所以,看着答案,我問 - 為什么他們不掛鈎 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()

解決問題的方法與將兩個小部件連接到單個滾動條的方法幾乎相同:為鼠標滾輪創建自定義綁定並使這些綁定影響兩個列表框,而不僅僅是一個。

唯一真正的技巧是知道您會根據平台獲得不同的鼠標滾輪事件: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()

這是我當前的解決方案,編碼為獨立函數(是的,它應該是一個對象)。

特點/要求:

  • 它處理任意數量的列表(最少 1 個)。
  • 所有列表目前必須具有相同的長度。
  • 調整每個列表框寬度的寬度以匹配內容。
  • 列表框使用鼠標滾輪或滾動條一起滾動。
  • 應該適用於 Windows、OSX 和 Linux,但僅在 Linux 上進行過測試。

代碼:

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

歡迎提出改進建議!

我做了一個非常簡單的程序解決方案。 在教程點站點上查看有關如何將滾動條用於一個小部件 ( https://www.tutorialspoint.com/python/tk_scrollbar.htm ) 的信息后,我將其調整為同時滾動多個文本框 (您可以更改代碼,使其使用列表框)。 當您使用滾動條時,此解決方案將更新所有三個文本框。

import tkinter as tk

HEIGHT = 200
WIDTH = 300

def scroll(x, y):
    l_textbox.yview(x,y)
    m_textbox.yview(x,y)
    r_textbox.yview(x,y)

root = tk.Tk()

canvas = tk.Canvas(root,height = HEIGHT, width = WIDTH, bg = "white")
canvas.pack()

frame = tk.Frame(root, bg ='white')
frame.place(relx=0,rely=0,relwidth=1,relheight=1)

scrollbar = tk.Scrollbar(frame)

l_label = tk.Label (frame, text = "Left")
l_label.place(relx=0, rely=0)

m_label = tk.Label (frame, text= "Middle")
m_label.place(relx=0.3, rely=0)

r_label = tk.Label (frame, text= "Right")
r_label.place(relx=0.6, rely=0)

l_textbox = tk.Text(frame, yscrollcommand = scrollbar.set)
l_textbox.config(font = ('Arial',9))
l_textbox.place(relx=0, rely=0.2,relwidth=0.3,relheight=0.8)

m_textbox = tk.Text(frame, yscrollcommand = scrollbar.set)
m_textbox.config(font = ('Arial',9))
m_textbox.place(relx=0.3, rely=0.2,relwidth=0.3,relheight=0.8)

r_textbox = tk.Text(frame, yscrollcommand = scrollbar.set)
r_textbox.config(font = ('Arial',9))
r_textbox.place(relx=0.6, rely=0.2,relwidth=0.3,relheight=0.8)

scrollbar.config( command = scroll)
scrollbar.place(relx = 0.9, relwidth = 0.1,relheight = 1)

for i in range(0, 100):
    l_textbox.insert(tk.INSERT, str(i)+"\n")
    m_textbox.insert(tk.INSERT, str(i)+"\n")
    r_textbox.insert(tk.INSERT, str(i)+"\n")
    l_textbox.place()
    m_textbox.place()
    r_textbox.place()

root.mainloop()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM