Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter a ttk.treeview in Python?

I have a python tkinter application that contains a ttk.treeview widget.

The widget displays a list of files found on a specific directory tree with a specific extension - this was trivial to build with tt.treeview widget.

There is a request to enable "on-the-fly" filtering of the tree - e.g., the user types in an Entry some string, and as he/she types, the tree removes elements that don't match the typed string so far.

I was exploring the Treeview documentation, tried the detach and reattach methods but with no luck.

detach indeed removes the non-matched elements from the tree, but if the user hit Backspace, I can no longer iterate correctly on the tree to restore those detached elements as get_children method will not return them.

def filter_tree(self):
    search_by = self.search_entry.get()
    self.tree_detach_leaf_by_regex(self.current_loaded_folder, search_by, "")

def tree_detach_leaf_by_regex(self, root, regex, parent):
    if self.treeview.get_children(root):
        for child in self.treeview.get_children(root):
            self.tree_detach_leaf_by_regex(child, regex, root)
    else:
        if not re.match(regex, self.treeview.item(root)["text"]):
            self.elements_index_within_parent[root] = self.treeview.index(root)
            self.elements_parents[parent] = 1
            self.treeview.detach(root)
        else:
            self.treeview.reattach(root, parent, self.elements_index_within_parent[root])

Looking forward to read your advice.

like image 1000
NirMH Avatar asked Jun 15 '17 10:06

NirMH


People also ask

How do I edit a Treeview in Python?

The Treeview widget items can be edited and deleted by selecting the item using tree. selection() function. Once an item is selected, we can perform certain operations to delete or edit the item.

What is TTK Treeview?

The purpose of the ttk . Treeview widget is to present a hierarchical structure so that the user can use mouse actions to reveal or hide any part of the structure.

How do I delete an item in Treeview?

If we want to remove or clear all the items in a given treeview widget, then we have to first select all the items present in the treeview widget using get_children() method. Once we have selected all the treeview items programmatically, then we can delete the items using delete(item) method.

How do I disable Treeview in Python?

The Treeview widget is used to display a list of items with more than one feature in the form of columns. By default, the listed items in a Treeview widget can be selected multiple times, however you can disable this feature by using selectmode="browse" in the Treeview widget constructor.


1 Answers

To make my answer reusable by anybody, I have to tell more than directly answering your question. If you directly want to see how I do to get detached items (thus without using the method get_children which cannot get detached items' id), jump to the definition of the method whose name is _columns_searcher.


Introduction

Let's first define some attributes.

@property
def _to_search(self):
    key = 'to_search'
    if key not in self._cache:
        self._cache[key] = tk.StringVar()
    return self._cache[key] 

def _set_search_entry(self):  
    ent = ttk.Entry(
        self.root, # or canvas, or frame ...
        #...
        textvariable=self._to_search
    )
    ent.grid(
        #...
    )
    ent.bind(
        '<Return>',
        self._columns_searcher
    )
    return ent

@property
def search_entry(self):
    key = 'search_entry'
    if key not in self._cache:
        self._cache[key] = self._set_search_entry()
    return self._cache[key]


Core answer

What follows is the part which directly show how to re-attach user-detached items. First note that, as the OP mentions, get_children only return ids of attached items. Second note that the only thing you need to re-attach detached items is their id. Which implies thus to trace/save them when they are detached so as to be able to re-attach them.

_detached = set()
def _columns_searcher(self, event):
    #              originally a set            returns a tuple
    children = list(self._detached) + list(self.tree.get_children())
    self._detached = set()
    query = self._to_search.get()

    self._brut_searcher(children, query.lower())

Note that children above contains all items, be them detached.

def _brut_searcher(self, children, query):
    i_r = -1
    for item_id in children:
        text = self.tree.item(item_id)['text'] # already contains the strin-concatenation (over columns) of the row's values
        if query in text:
            i_r += 1
            self.tree.reattach(item_id, '', i_r)
        else:
            self._detached.add(item_id)
            self.tree.detach(item_id)
like image 159
keepAlive Avatar answered Oct 23 '22 05:10

keepAlive