Python: listbox with multiple columns in Tkinter - sort columns by clicking on them

Asked

Viewed 637 times

0

I have a listbox with multiple columns, as shown below.

I would like to sort the columns by clicking on the titles of them, see the code:

I had thought within the "sortby()" function to identify when they clicked on each title and so called an ordered list.

For this hypothesis I would need to update the variable "database" there at the end of the code and make the listbox load (update) the window. I can’t do this.

If you can help me, I’d like to thank you.

If you check another way, please inform me. Thank you.

inserir a descrição da imagem aqui

import operator
try:
    import Tkinter as tk
    import tkFont
    import ttk
except ImportError:
    import tkinter as tk
    import tkinter.font as tkFont
    import tkinter.ttk as ttk

class 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):
        container = ttk.Frame()
        container.place(x=5, y=5, width=1170)

        # create a treeview with dual scrollbars
        self.tree = ttk.Treeview(columns=titulos_listbox, 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 titulos_listbox:
            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 banco_dados:
            self.tree.insert('', 'end', values=item)


def sortby(tree, col, descending):
    """sort tree contents when a column header is clicked on"""
    data = [(tree.set(child, col), child) \
        for child in tree.get_children('')]

    if col == "Data":
        print("Data")
        # bd = sorted(banco_dados, key=operator.itemgetter(0)) # sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(0)) # alterando a lista
        print(banco_dados)

    elif col == "Código":
        print("Código")
        # bd = sorted(banco_dados, key=operator.itemgetter(1))# sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(1)) # alterando a lista
        print(banco_dados)

    elif col == "Item":
        print("Item")
        # bd = sorted(banco_dados, key=operator.itemgetter(2))# sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(2)) # alterando a lista
        print(banco_dados)

    elif col == "Quantidade":
        print("Quantidade")
        # bd = sorted(banco_dados, key=operator.itemgetter(3))# sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(3)) # alterando a lista
        print(banco_dados)

    elif col == "Custo unitário":
        print("Custo unitário")
        # bd = sorted(banco_dados, key=operator.itemgetter(4))# sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(4)) # alterando a lista
        print(banco_dados)

    elif col == "Custo total":
        print("Custo total")
        # bd = sorted(banco_dados, key=operator.itemgetter(5))# sem alterar a lista
        bd = banco_dados.sort(key=operator.itemgetter(5)) # alterando a lista
        print(banco_dados)


titulos_listbox = ['Data', 'Código', 'Item', 'Quantidade', 'Custo unitário', 'Custo total']
banco_dados = [('01/01/2019', 000, 'item 000', 555, 666.0, 9999999.0, ''),
               ('01/01/2019', 111, 'item 111', 111, 111.0, 111.0, 'obs1'),
               ('02/01/2019', 333, 'item 333', 222, 222.0, 222.0, 'obs2'),
               ('03/01/2019', 777, 'item 777', 333, 333.0, 333.0, 'obs 3'),
               ('04/01/2019', 444, 'item 444', 4444, 4444.0, 4444.0, 'obs 4'),
               ('05/01/2019', 222, 'item 222', 5555, 5555.0, 5555.0, 'obs 5'),
               ('06/01/2019', 888, 'item 888', 6666, 6666.0, 6666.0, 'obs 6')]


if __name__ == '__main__':
    root = tk.Tk()
    root.title("listbox")
    root["bg"] = "LightSteelBlue"
    root.geometry('1180x255+5+40')
    listbox = MultiColumnListbox()
    root.mainloop()

1 answer

1


Keeping the rest of the code equal, replace the method sortby() for this:

def sortby(tree, col, descending):
    l = [(tree.set(k, col), k) for k in tree.get_children('')]
    l.sort(reverse=descending)

    # ordena itens
    for index, (val, k) in enumerate(l):
        tree.move(k, '', index)

    # inversão da ordem
    tree.heading(col, command=lambda: sortby(tree, col, not descending))
  • 1

    Thank you @alandplm I was since 9 am trying.

  • Thanks to @Wilsonjunior!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.