Search code examples
pythontkintertreeviewtreeviewitem

search and select item in treeview tkinter python


I would like to create search_function to search data in treeview table. On my code, I do need to click search_button to select data in treeview table following my 3 request below.

from tkinter import *
from tkinter import ttk

GUI = Tk()
GUI.geometry('1920x1080')

tree_view_frame = Frame(GUI)
tree_view_frame.pack()
tree_scroll = Scrollbar(tree_view_frame)
tree_scroll.pack(side = RIGHT, fill = Y)
header = ['Part No.', 'Name', 'Unit', 'Quan', 'Price','Total', 'Initial Total']
hdsize = [60,240,60,60,70,80,80]
aanchor = [W,W,E,E,E,E,E]
global product_table
product_table = ttk.Treeview(tree_view_frame, columns = header, show = 'headings', height = 20, yscrollcommand=tree_scroll.set, selectmode="extended")
def treeview_sort_column(product_table, col, reverse):
    l = [(product_table.set(k, col), k) for k in product_table.get_children('')]
    l.sort(reverse=reverse)
    for index, (val, k) in enumerate(l):
        product_table.move(k, '', index)
    product_table.heading(col, command=lambda _col=col: treeview_sort_column(product_table, _col, not reverse))
for col in header:
    product_table.heading(col, text=col,command=lambda _col=col: treeview_sort_column(product_table, _col, False))
product_table.pack()
tree_scroll.config(command = product_table.yview)
for h,s,a in zip(header, hdsize, aanchor):
    product_table.heading(h, text = h)
    product_table.column(h,width = s, anchor = a)

Nameget = StringVar()
E_namme = ttk.Entry(GUI,textvariable = Nameget)
E_namme.pack()

def Add_Product(event = None):
    product_table.insert('', 'end', value = ('', Nameget.get()))
B_Add_product = ttk.Button(GUI, text = "Add Product", command = Add_Product)
B_Add_product.pack()

def search_function():
    query = Nameget.get()
    selections = []
    for child in product_table.get_children():
        if query in product_table.item(child)['values'][1]:
            selections.append(child)
            product_table.selection_set(selections[0])
            product_table.focus(selections[0])
    product_table.focus_force()
search_button = ttk.Button(GUI, text = "search_button", width = 15, command = search_function)
search_button.pack()

GUI.mainloop()
  1. for first click is to select the first result. enter image description here

  2. second or next click is to select the next result until last result and do it as loop. enter image description here

  3. auto scroll down the scrollbar to select the result when it not appear in the current page. enter image description here

In the current code, it can select only the first result and not auto scroll down the scrollbar.

Thank you in advance.


Solution

  • You can use see (ensures that item is visible) and loop over.

    Any data structure can assist here use queue or dict like the example below:

    (It is good to use some OOP)

    from tkinter import *
    from tkinter import ttk
    from collections import defaultdict
    
    GUI = Tk()
    GUI.geometry("1920x1080")
    
    tree_view_frame = Frame(GUI)
    tree_view_frame.pack()
    tree_scroll = Scrollbar(tree_view_frame)
    tree_scroll.pack(side=RIGHT, fill=Y)
    header = ["Part No.", "Name", "Unit", "Quan", "Price", "Total", "Initial Total"]
    hdsize = [60, 240, 60, 60, 70, 80, 80]
    aanchor = [W, W, E, E, E, E, E]
    global product_table
    
    
    class ProductMap:
        def __init__(self):
            self.selections = defaultdict(list)
            self.last_lookup = ""
    
        def treeview_sort_column(self, product_table, col, reverse):
            l = [(product_table.set(k, col), k) for k in product_table.get_children("")]
            l.sort(reverse=reverse)
            for index, (val, k) in enumerate(l):
                product_table.move(k, "", index)
            product_table.heading(
                col,
                command=lambda _col=col: product_map.treeview_sort_column(
                    product_table, _col, not reverse
                ),
            )
    
        def search_function(self):
            query = Nameget.get()
            if not query:
                return
            children = product_table.get_children()
            for child in children:
                curr = product_table.item(child)["values"][1]
                if query in curr and child not in self.selections[query]:
                    self.selections[query].append(child)
                    product_table.selection_set(child)
                    product_table.focus(child)
                    product_table.see(child)
                    self.last_lookup = query
                    return
                elif query != self.last_lookup:
                    self.selections = defaultdict(list)
    
        def Add_Product(self, event=None):
            product_table.insert("", "end", value=("", Nameget.get()))
    
    
    product_map = ProductMap()
    
    product_table = ttk.Treeview(
        tree_view_frame,
        columns=header,
        show="headings",
        height=20,
        yscrollcommand=tree_scroll.set,
        selectmode="extended",
    )
    for col in header:
        product_table.heading(
            col,
            text=col,
            command=lambda _col=col: product_map.treeview_sort_column(
                product_table, _col, False
            ),
        )
    product_table.pack()
    tree_scroll.config(command=product_table.yview)
    for h, s, a in zip(header, hdsize, aanchor):
        product_table.heading(h, text=h)
        product_table.column(h, width=s, anchor=a)
    
    Nameget = StringVar()
    E_namme = ttk.Entry(GUI, textvariable=Nameget)
    E_namme.pack()
    
    
    B_Add_product = ttk.Button(GUI, text="Add Product", command=product_map.Add_Product)
    B_Add_product.pack()
    
    
    search_button = ttk.Button(
        GUI, text="search_button", width=15, command=product_map.search_function
    )
    search_button.pack()
    
    
    GUI.mainloop()