• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from tkinter import *
2from tkinter.ttk import Scrollbar
3
4from idlelib import macosx
5
6
7class ScrolledList:
8
9    default = "(None)"
10
11    def __init__(self, master, **options):
12        # Create top frame, with scrollbar and listbox
13        self.master = master
14        self.frame = frame = Frame(master)
15        self.frame.pack(fill="both", expand=1)
16        self.vbar = vbar = Scrollbar(frame, name="vbar")
17        self.vbar.pack(side="right", fill="y")
18        self.listbox = listbox = Listbox(frame, exportselection=0,
19            background="white")
20        if options:
21            listbox.configure(options)
22        listbox.pack(expand=1, fill="both")
23        # Tie listbox and scrollbar together
24        vbar["command"] = listbox.yview
25        listbox["yscrollcommand"] = vbar.set
26        # Bind events to the list box
27        listbox.bind("<ButtonRelease-1>", self.click_event)
28        listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
29        if macosx.isAquaTk():
30            listbox.bind("<ButtonPress-2>", self.popup_event)
31            listbox.bind("<Control-Button-1>", self.popup_event)
32        else:
33            listbox.bind("<ButtonPress-3>", self.popup_event)
34        listbox.bind("<Key-Up>", self.up_event)
35        listbox.bind("<Key-Down>", self.down_event)
36        # Mark as empty
37        self.clear()
38
39    def close(self):
40        self.frame.destroy()
41
42    def clear(self):
43        self.listbox.delete(0, "end")
44        self.empty = 1
45        self.listbox.insert("end", self.default)
46
47    def append(self, item):
48        if self.empty:
49            self.listbox.delete(0, "end")
50            self.empty = 0
51        self.listbox.insert("end", str(item))
52
53    def get(self, index):
54        return self.listbox.get(index)
55
56    def click_event(self, event):
57        self.listbox.activate("@%d,%d" % (event.x, event.y))
58        index = self.listbox.index("active")
59        self.select(index)
60        self.on_select(index)
61        return "break"
62
63    def double_click_event(self, event):
64        index = self.listbox.index("active")
65        self.select(index)
66        self.on_double(index)
67        return "break"
68
69    menu = None
70
71    def popup_event(self, event):
72        if not self.menu:
73            self.make_menu()
74        menu = self.menu
75        self.listbox.activate("@%d,%d" % (event.x, event.y))
76        index = self.listbox.index("active")
77        self.select(index)
78        menu.tk_popup(event.x_root, event.y_root)
79
80    def make_menu(self):
81        menu = Menu(self.listbox, tearoff=0)
82        self.menu = menu
83        self.fill_menu()
84
85    def up_event(self, event):
86        index = self.listbox.index("active")
87        if self.listbox.selection_includes(index):
88            index = index - 1
89        else:
90            index = self.listbox.size() - 1
91        if index < 0:
92            self.listbox.bell()
93        else:
94            self.select(index)
95            self.on_select(index)
96        return "break"
97
98    def down_event(self, event):
99        index = self.listbox.index("active")
100        if self.listbox.selection_includes(index):
101            index = index + 1
102        else:
103            index = 0
104        if index >= self.listbox.size():
105            self.listbox.bell()
106        else:
107            self.select(index)
108            self.on_select(index)
109        return "break"
110
111    def select(self, index):
112        self.listbox.focus_set()
113        self.listbox.activate(index)
114        self.listbox.selection_clear(0, "end")
115        self.listbox.selection_set(index)
116        self.listbox.see(index)
117
118    # Methods to override for specific actions
119
120    def fill_menu(self):
121        pass
122
123    def on_select(self, index):
124        pass
125
126    def on_double(self, index):
127        pass
128
129
130def _scrolled_list(parent):  # htest #
131    top = Toplevel(parent)
132    x, y = map(int, parent.geometry().split('+')[1:])
133    top.geometry("+%d+%d" % (x+200, y + 175))
134    class MyScrolledList(ScrolledList):
135        def fill_menu(self): self.menu.add_command(label="right click")
136        def on_select(self, index): print("select", self.get(index))
137        def on_double(self, index): print("double", self.get(index))
138
139    scrolled_list = MyScrolledList(top)
140    for i in range(30):
141        scrolled_list.append("Item %02d" % i)
142
143if __name__ == '__main__':
144    # At the moment, test_scrolledlist merely creates instance, like htest.
145    from idlelib.idle_test.htest import run
146    run(_scrolled_list)
147