Display Listbox with columns using Tkinter? Display Listbox with columns using Tkinter? tkinter tkinter

Display Listbox with columns using Tkinter?


You can use Ttk/Tkinker Treeview widget, which is used to work with tabular data.

The following is an example of a class that uses a Treeview widget to display a multi-column list of strings:

'''Here the TreeView widget is configured as a multi-column listboxwith adjustable column width and column-header-click sorting.'''try:    import Tkinter as tk    import tkFont    import ttkexcept ImportError:  # Python 3    import tkinter as tk    import tkinter.font as tkFont    import tkinter.ttk as ttkclass MultiColumnListbox(object):    """use a ttk.TreeView as a multicolumn ListBox"""    def __init__(self):        self.tree = None        self._setup_widgets()        self._build_tree()    def _setup_widgets(self):        s = """\click on header to sort by that columnto change width of column drag boundary        """        msg = ttk.Label(wraplength="4i", justify="left", anchor="n",            padding=(10, 2, 10, 6), text=s)        msg.pack(fill='x')        container = ttk.Frame()        container.pack(fill='both', expand=True)        # create a treeview with dual scrollbars        self.tree = ttk.Treeview(columns=car_header, show="headings")        vsb = ttk.Scrollbar(orient="vertical",            command=self.tree.yview)        hsb = ttk.Scrollbar(orient="horizontal",            command=self.tree.xview)        self.tree.configure(yscrollcommand=vsb.set,            xscrollcommand=hsb.set)        self.tree.grid(column=0, row=0, sticky='nsew', in_=container)        vsb.grid(column=1, row=0, sticky='ns', in_=container)        hsb.grid(column=0, row=1, sticky='ew', in_=container)        container.grid_columnconfigure(0, weight=1)        container.grid_rowconfigure(0, weight=1)    def _build_tree(self):        for col in car_header:            self.tree.heading(col, text=col.title(),                command=lambda c=col: sortby(self.tree, c, 0))            # adjust the column's width to the header string            self.tree.column(col,                width=tkFont.Font().measure(col.title()))        for item in car_list:            self.tree.insert('', 'end', values=item)            # adjust column's width if necessary to fit each value            for ix, val in enumerate(item):                col_w = tkFont.Font().measure(val)                if self.tree.column(car_header[ix],width=None)<col_w:                    self.tree.column(car_header[ix], width=col_w)def sortby(tree, col, descending):    """sort tree contents when a column header is clicked on"""    # grab values to sort    data = [(tree.set(child, col), child) \        for child in tree.get_children('')]    # if the data to be sorted is numeric change to float    #data =  change_numeric(data)    # now sort the data in place    data.sort(reverse=descending)    for ix, item in enumerate(data):        tree.move(item[1], '', ix)    # switch the heading so it will sort in the opposite direction    tree.heading(col, command=lambda col=col: sortby(tree, col, \        int(not descending)))# the test data ...car_header = ['car', 'repair']car_list = [('Hyundai', 'brakes') ,('Honda', 'light') ,('Lexus', 'battery') ,('Benz', 'wiper') ,('Ford', 'tire') ,('Chevy', 'air') ,('Chrysler', 'piston') ,('Toyota', 'brake pedal') ,('BMW', 'seat')]if __name__ == '__main__':    root = tk.Tk()    root.title("Multicolumn Treeview/Listbox")    listbox = MultiColumnListbox()    root.mainloop()

These are some pictures of the result of using a Treeview widget:

enter image description here


Using TkTreectrl:

import Tkinter as tkimport TkTreectrl as treectrlimport sqlite3def setup_table(connection):    cursor=connection.cursor()    cursor.execute('''CREATE TABLE foo                      (id INTEGER PRIMARY KEY AUTOINCREMENT,                      bar TEXT)''')    sql='INSERT INTO foo (bar) values (?)'    for i in range(10):        cursor.execute(sql,(i,))    cursor.execute(sql,(u'\N{INFINITY}',))def select_cmd(selected):    print 'Selected items:', selecteddef main():    connection=sqlite3.connect(':memory:')       setup_table(connection)    cursor=connection.cursor()    root = tk.Tk()    root.title('Simple MultiListbox demo')    mlb = treectrl.MultiListbox(root)    mlb.pack(side='top', fill='both', expand=1)    tk.Button(root, text='Close', command=root.quit).pack(side='top', pady=5)    mlb.focus_set()       mlb.configure(selectcmd=select_cmd, selectmode='extended')    mlb.config(columns=('Column 1', 'Column 2'))    cursor.execute('SELECT * from foo')    for row in cursor.fetchall():        mlb.insert('end',*map(unicode,row))    root.mainloop()if __name__=='__main__':    main()

yields

enter image description here


One simple solution is to use two listboxes side-by-side. There's no real magic, you just have to do a little bit of extra work to get one scrollbar to control both (easily done) and have the selection in the two sync up (also easily done).