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