ScrolledList.py 3.9 KB
Newer Older
1 2 3
from Tkinter import *

class ScrolledList:
Tim Peters's avatar
Tim Peters committed
4

Guido van Rossum's avatar
Guido van Rossum committed
5
    default = "(None)"
Guido van Rossum's avatar
Guido van Rossum committed
6

7 8 9 10 11 12 13
    def __init__(self, master, **options):
        # Create top frame, with scrollbar and listbox
        self.master = master
        self.frame = frame = Frame(master)
        self.frame.pack(fill="both", expand=1)
        self.vbar = vbar = Scrollbar(frame, name="vbar")
        self.vbar.pack(side="right", fill="y")
Guido van Rossum's avatar
Guido van Rossum committed
14 15
        self.listbox = listbox = Listbox(frame, exportselection=0,
            background="white")
16 17 18 19 20 21 22 23
        if options:
            listbox.configure(options)
        listbox.pack(expand=1, fill="both")
        # Tie listbox and scrollbar together
        vbar["command"] = listbox.yview
        listbox["yscrollcommand"] = vbar.set
        # Bind events to the list box
        listbox.bind("<ButtonRelease-1>", self.click_event)
Guido van Rossum's avatar
Guido van Rossum committed
24
        listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
25 26 27
        listbox.bind("<ButtonPress-3>", self.popup_event)
        listbox.bind("<Key-Up>", self.up_event)
        listbox.bind("<Key-Down>", self.down_event)
Guido van Rossum's avatar
Guido van Rossum committed
28 29
        # Mark as empty
        self.clear()
Guido van Rossum's avatar
Guido van Rossum committed
30

Guido van Rossum's avatar
Guido van Rossum committed
31 32
    def close(self):
        self.frame.destroy()
Guido van Rossum's avatar
Guido van Rossum committed
33

34 35
    def clear(self):
        self.listbox.delete(0, "end")
Guido van Rossum's avatar
Guido van Rossum committed
36 37
        self.empty = 1
        self.listbox.insert("end", self.default)
Guido van Rossum's avatar
Guido van Rossum committed
38

39
    def append(self, item):
Guido van Rossum's avatar
Guido van Rossum committed
40 41 42
        if self.empty:
            self.listbox.delete(0, "end")
            self.empty = 0
43
        self.listbox.insert("end", str(item))
Guido van Rossum's avatar
Guido van Rossum committed
44

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
    def get(self, index):
        return self.listbox.get(index)

    def click_event(self, event):
        self.listbox.activate("@%d,%d" % (event.x, event.y))
        index = self.listbox.index("active")
        self.select(index)
        self.on_select(index)
        return "break"

    def double_click_event(self, event):
        index = self.listbox.index("active")
        self.select(index)
        self.on_double(index)
        return "break"
Guido van Rossum's avatar
Guido van Rossum committed
60

61
    menu = None
Guido van Rossum's avatar
Guido van Rossum committed
62

63 64 65 66 67 68 69 70 71 72 73 74 75
    def popup_event(self, event):
        if not self.menu:
            self.make_menu()
        menu = self.menu
        self.listbox.activate("@%d,%d" % (event.x, event.y))
        index = self.listbox.index("active")
        self.select(index)
        menu.tk_popup(event.x_root, event.y_root)

    def make_menu(self):
        menu = Menu(self.listbox, tearoff=0)
        self.menu = menu
        self.fill_menu()
Guido van Rossum's avatar
Guido van Rossum committed
76

77 78 79 80 81 82 83 84 85 86 87 88
    def up_event(self, event):
        index = self.listbox.index("active")
        if self.listbox.selection_includes(index):
            index = index - 1
        else:
            index = self.listbox.size() - 1
        if index < 0:
            self.listbox.bell()
        else:
            self.select(index)
            self.on_select(index)
        return "break"
Guido van Rossum's avatar
Guido van Rossum committed
89

90 91 92 93 94 95 96 97 98 99 100 101
    def down_event(self, event):
        index = self.listbox.index("active")
        if self.listbox.selection_includes(index):
            index = index + 1
        else:
            index = 0
        if index >= self.listbox.size():
            self.listbox.bell()
        else:
            self.select(index)
            self.on_select(index)
        return "break"
Guido van Rossum's avatar
Guido van Rossum committed
102

103 104 105 106 107 108
    def select(self, index):
        self.listbox.focus_set()
        self.listbox.activate(index)
        self.listbox.selection_clear(0, "end")
        self.listbox.selection_set(index)
        self.listbox.see(index)
Guido van Rossum's avatar
Guido van Rossum committed
109

110
    # Methods to override for specific actions
Guido van Rossum's avatar
Guido van Rossum committed
111

112 113
    def fill_menu(self):
        pass
Guido van Rossum's avatar
Guido van Rossum committed
114

115 116
    def on_select(self, index):
        pass
Guido van Rossum's avatar
Guido van Rossum committed
117

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    def on_double(self, index):
        pass


def test():
    root = Tk()
    root.protocol("WM_DELETE_WINDOW", root.destroy)
    class MyScrolledList(ScrolledList):
        def fill_menu(self): self.menu.add_command(label="pass")
        def on_select(self, index): print "select", self.get(index)
        def on_double(self, index): print "double", self.get(index)
    s = MyScrolledList(root)
    for i in range(30):
        s.append("item %02d" % i)
    return root

def main():
    root = test()
    root.mainloop()

if __name__ == '__main__':
    main()