create top frame with scrollbar and listbox tie listbox and scrollbar together bind events to the list box mark as empty methods to override for specific actions create top frame with scrollbar and listbox tie listbox and scrollbar together bind events to the list box mark as empty methods to override for specific actions htest
from tkinter import *
from tkinter.ttk import Frame, Scrollbar

from idlelib import macosx


class ScrolledList:

    default = "(None)"

    def __init__(self, master, **options):
        
        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")
        self.listbox = listbox = Listbox(frame, exportselection=0,
            background="white")
        if options:
            listbox.configure(options)
        listbox.pack(expand=1, fill="both")
        
        vbar["command"] = listbox.yview
        listbox["yscrollcommand"] = vbar.set
        
        listbox.bind("<ButtonRelease-1>", self.click_event)
        listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
        if macosx.isAquaTk():
            listbox.bind("<ButtonPress-2>", self.popup_event)
            listbox.bind("<Control-Button-1>", self.popup_event)
        else:
            listbox.bind("<ButtonPress-3>", self.popup_event)
        listbox.bind("<Key-Up>", self.up_event)
        listbox.bind("<Key-Down>", self.down_event)
        
        self.clear()

    def close(self):
        self.frame.destroy()

    def clear(self):
        self.listbox.delete(0, "end")
        self.empty = 1
        self.listbox.insert("end", self.default)

    def append(self, item):
        if self.empty:
            self.listbox.delete(0, "end")
            self.empty = 0
        self.listbox.insert("end", str(item))

    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"

    menu = None

    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)
        return "break"

    def make_menu(self):
        menu = Menu(self.listbox, tearoff=0)
        self.menu = menu
        self.fill_menu()

    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"

    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"

    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)

    

    def fill_menu(self):
        pass

    def on_select(self, index):
        pass

    def on_double(self, index):
        pass


def _scrolled_list(parent):  
    top = Toplevel(parent)
    x, y = map(int, parent.geometry().split('+')[1:])
    top.geometry("+%d+%d" % (x+200, y + 175))
    class MyScrolledList(ScrolledList):
        def fill_menu(self): self.menu.add_command(label="right click")
        def on_select(self, index): print("select", self.get(index))
        def on_double(self, index): print("double", self.get(index))

    scrolled_list = MyScrolledList(top)
    for i in range(30):
        scrolled_list.append("Item %02d" % i)

if __name__ == '__main__':
    from unittest import main
    main('idlelib.idle_test.test_scrolledlist', verbosity=2,)

    from idlelib.idle_test.htest import run
    run(_scrolled_list)