2

I am trying to implement search in ttk.treeview table. There are obviously some answers already and I am using one of them (see the code below). However I want to extend the question.

Given the code below, how to make it so that in addition to highlighting the required element the view will scroll to that element?
In other words, in case we will have more elements in the list that fit in the view and the one we are searching for is at the bottom, how to bring it say to the middle (or top will be better?) of the view during the act of inputting characters into the search field? Also since it is possible to highlight multiple elements at once, I guess we should scroll to the first element.

from tkinter import *
from tkinter import ttk

class App:
    def __init__(self, root):
        self.root = root
        self.tree = ttk.Treeview(self.root) #create tree
        self.sv = StringVar() #create stringvar for entry widget
        self.sv.trace("w", self.command) #callback if stringvar is updated
        self.entry = Entry(self.root, textvariable=self.sv) #create entry
        self.names = [
            "tawymu","uzzkhv","mimfms","qpugux","mswzaz","alexsa","khfpke",
            "fsphkn","indzsl","rmvuag","gvrmxd","vfshxx","kwpuyz","pyfmar",
        ]  # these are just test inputs for the tree
        self.ids = [] #creates a list to store the ids of each entry in the tree
        for i in range(len(self.names)):
            #creates an entry in the tree for each element of the list
            #then stores the id of the tree in the self.ids list
            self.ids.append(self.tree.insert("", "end", text=self.names[i]))
        self.tree.pack()
        self.entry.pack()
    def command(self, *args):
        self.selections = [] #list of ids of matching tree entries
        for i in range(len(self.names)):
            #the below if check checks if the value of the entry matches the first characters of each element
            #in the names list up to the length of the value of the entry widget
            if self.entry.get() != "" and self.entry.get() == self.names[i][:len(self.entry.get())]:
                self.selections.append(self.ids[i]) #if it matches it appends the id to the selections list
        self.tree.selection_set(self.selections) #we then select every id in the list

root = Tk()
App(root)
root.mainloop()
user2333940
  • 113
  • 8
  • One solution are, calculate the row position of the first highlighted row relativ to the `scrollregion` and use `self.tree.yview_moveto()`. – stovfl Feb 24 '19 at 18:42

2 Answers2

6

There's a see method for treeview.

def command(self, *args):
    self.selections = []
    for i in range(len(self.names)):
        if self.entry.get() != "" and self.entry.get() == self.names[i][:len(self.entry.get())]:
            self.selections.append(self.ids[i])
    self.tree.selection_set(self.selections)
    try:
        self.tree.see(self.selections[0]) #you can iterate through the list for multiple selection
    except IndexError:
        pass
Henry Yik
  • 22,275
  • 4
  • 18
  • 40
1

I found a hack to bring my row of interest to the top of the window. First scrow to the bottom and then back up.

tree.see(items[-1])
tree.see(items[my_target_item_n])