Skip to content Skip to sidebar Skip to footer

How To Create A Button Or Option Which Allows A User To Filter A Treeview Based On A Value In A Column (python)?

I have created a GUI where volume data is being displayed based on a currency selection from a drop down menu. The displayed dataframe looks like the example below. The dataframe i

Solution 1:

I improved upon the answer of @Henry Yik - This version will create a filter for all available columns, and you will be able to filter multiple columns at the same time. It does however rely on the fact that all columns contain strings to do proper matching

from tkinter import *
from tkinter import ttk

inp = [{'Currency': 'EUR', 'Volume': '100', 'Country': 'SE'},
       {'Currency': 'GBR', 'Volume': '200', 'Country': 'SE'},
       {'Currency': 'CAD', 'Volume': '300', 'Country': 'SE'},
       {'Currency': 'EUR', 'Volume': '400', 'Country': 'SE'},
       {'Currency': 'EUR', 'Volume': '100', 'Country': 'DK'},
       {'Currency': 'GBR', 'Volume': '200', 'Country': 'DK'},
       {'Currency': 'CAD', 'Volume': '300', 'Country': 'DK'},
       {'Currency': 'EUR', 'Volume': '400', 'Country': 'DK'},
       ]


class Application(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title("Volume")

        combofr = Frame(self)
        combofr.pack(expand=True, fill=X)
        self.tree = ttk.Treeview(self, show='headings')
        columns = list(inp[0].keys())

        self.filters = []

        for col in columns:
            name = 'combo_' + col
            self.filters.append(name)
            setattr(self, name, ttk.Combobox(combofr, values=[''] + sorted(set(x[col] for x in inp)), state="readonly"))
            getattr(self, name).pack(side=LEFT, expand=True, fill=X)
            getattr(self, name).bind('<<ComboboxSelected>>', self.select_from_filters)

        self.tree["columns"] = columns
        self.tree.pack(expand=TRUE, fill=BOTH)

        for i in columns:
            self.tree.column(i, anchor="w")
            self.tree.heading(i, text=i, anchor="w")

        for i, row in enumerate(inp):
            self.tree.insert("", "end", text=i, values=list(row.values()))

    def select_from_filters(self, event=None):
        self.tree.delete(*self.tree.get_children())

        all_filter = lambda x: all(x[f.split('_')[-1]] == getattr(self, f).get() or getattr(self, f).get() == '' for f in self.filters)
        for row in inp:
            if all_filter(row):
                self.tree.insert("", "end", values=list(row.values()))


root = Application()
root.mainloop()

Solution 2:

You can create a selection box for the user and display only the filtered results. Below is a sample utilizing ttk.Combobox base on your code:

from tkinter import *
import pandas as pd
from tkinter import ttk

df = pd.DataFrame({"Currency":["EUR","GBR","CAD","EUR"],
                   "Volumne":[100,200,300,400]})

class Application(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title("Volume")

        self.tree = ttk.Treeview(self)
        columns = list(df.columns)
        self.combo = ttk.Combobox(self, values=list(df["Currency"].unique()),state="readonly")
        self.combo.pack()
        self.combo.bind("<<ComboboxSelected>>", self.select_currency)
        self.tree["columns"] = columns
        self.tree.pack(expand=TRUE, fill=BOTH)

        for i in columns:
            self.tree.column(i, anchor="w")
            self.tree.heading(i, text=i, anchor="w")

        for index, row in df.iterrows():
            self.tree.insert("", "end", text=index, values=list(row))

    def select_currency(self,event=None):
        self.tree.delete(*self.tree.get_children())
        for index, row in df.loc[df["Currency"].eq(self.combo.get())].iterrows():
            self.tree.insert("", "end", text=index, values=list(row))

root = Application()
root.mainloop()

Post a Comment for "How To Create A Button Or Option Which Allows A User To Filter A Treeview Based On A Value In A Column (python)?"