blob: 10229b63629293caa246ccc346edea7956a6db26 [file] [log] [blame]
Georg Brandl14fc4272008-05-17 18:39:55 +00001from tkinter import *
Terry Jan Reedy01e35752016-06-10 18:19:21 -04002from tkinter.ttk import Scrollbar
David Scherer7aced172000-08-15 01:13:23 +00003
Terry Jan Reedybfbaa6b2016-08-31 00:50:55 -04004from idlelib import macosx
5
6
David Scherer7aced172000-08-15 01:13:23 +00007class ScrolledList:
Kurt B. Kaiserbdaac362001-07-14 01:23:30 +00008
David Scherer7aced172000-08-15 01:13:23 +00009 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)
Terry Jan Reedy6fa5bdc2016-05-28 13:22:31 -040029 if macosx.isAquaTk():
Terry Jan Reedy00e4ce32015-09-26 18:50:26 -040030 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)
David Scherer7aced172000-08-15 01:13:23 +000034 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)
Serhiy Storchaka213ce122017-06-27 07:02:32 +030079 return "break"
David Scherer7aced172000-08-15 01:13:23 +000080
81 def make_menu(self):
82 menu = Menu(self.listbox, tearoff=0)
83 self.menu = menu
84 self.fill_menu()
85
86 def up_event(self, event):
87 index = self.listbox.index("active")
88 if self.listbox.selection_includes(index):
89 index = index - 1
90 else:
91 index = self.listbox.size() - 1
92 if index < 0:
93 self.listbox.bell()
94 else:
95 self.select(index)
96 self.on_select(index)
97 return "break"
98
99 def down_event(self, event):
100 index = self.listbox.index("active")
101 if self.listbox.selection_includes(index):
102 index = index + 1
103 else:
104 index = 0
105 if index >= self.listbox.size():
106 self.listbox.bell()
107 else:
108 self.select(index)
109 self.on_select(index)
110 return "break"
111
112 def select(self, index):
113 self.listbox.focus_set()
114 self.listbox.activate(index)
115 self.listbox.selection_clear(0, "end")
116 self.listbox.selection_set(index)
117 self.listbox.see(index)
118
119 # Methods to override for specific actions
120
121 def fill_menu(self):
122 pass
123
124 def on_select(self, index):
125 pass
126
127 def on_double(self, index):
128 pass
129
130
Terry Jan Reedy01e35752016-06-10 18:19:21 -0400131def _scrolled_list(parent): # htest #
132 top = Toplevel(parent)
Terry Jan Reedya7480322016-07-10 17:28:10 -0400133 x, y = map(int, parent.geometry().split('+')[1:])
134 top.geometry("+%d+%d" % (x+200, y + 175))
David Scherer7aced172000-08-15 01:13:23 +0000135 class MyScrolledList(ScrolledList):
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400136 def fill_menu(self): self.menu.add_command(label="right click")
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000137 def on_select(self, index): print("select", self.get(index))
138 def on_double(self, index): print("double", self.get(index))
David Scherer7aced172000-08-15 01:13:23 +0000139
Terry Jan Reedy01e35752016-06-10 18:19:21 -0400140 scrolled_list = MyScrolledList(top)
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400141 for i in range(30):
142 scrolled_list.append("Item %02d" % i)
143
David Scherer7aced172000-08-15 01:13:23 +0000144if __name__ == '__main__':
Terry Jan Reedy4d921582018-06-19 19:12:52 -0400145 from unittest import main
146 main('idlelib.idle_test.test_scrolledlist', verbosity=2,)
147
Terry Jan Reedy1b392ff2014-05-24 18:48:18 -0400148 from idlelib.idle_test.htest import run
149 run(_scrolled_list)