Python Forum
[Tkinter] Search data in treeview without search button - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: GUI (https://python-forum.io/forum-10.html)
+--- Thread: [Tkinter] Search data in treeview without search button (/thread-40524.html)



Search data in treeview without search button - TomasSanchexx - Aug-11-2023

Hello,
I'm trying to make an item search engine in a treeview, if I do it with a button, it works for me.
But I want to do the search without a button, just writing in the entry I select the closest thing.
I have done this, it does not give me any errors or anything, but it does not select any similar item or anything.

self.entry_buscador = tk.Entry()
        self.entry_buscador.place(x=150, y=142, width=450, height=40)
self.entry_buscador.bind("<<KeyRelease>>", self.buscar)
def buscar(self, event):
        self.query = self.entry_buscador.get().lower()

        for item in self.treeview_almacen.get_children():
            values = self.treeview_almacen.item(item, "values")
            if self.query in values[0].lower():
                self.treeview_almacen.selection_set(item)
                self.treeview_almacen.focus(item)
                self.treeview_almacen.see(item)
            else:
                self.treeview_almacen.selection_remove(item)
what do i have wrong? what can i do


RE: Search data in treeview without search button - deanhystad - Aug-11-2023

If you want people to answer your questions, you should ask good questions. Your question would benefit if you provided a runnable example. If I wanted to answer the question posted here, I need to write a tkinter program with an entry and a treeview. I would have to guess how the treeview should be created and what kind of data it is populated with. Only after doing all that could I do some work towards answering the question. Why would I want to do that? Sounds like a lot of work that should be done by the person asking for help.

But, to answer your question.

PROBLEM 1:
Your code with the button didn't work either, unless it was very different than the posted code. Your tree search only finds complete matches, not the "closest thing". If you want to do a partial match, you might want to use str.startswith(). This will find table entries that start with the same letters as in the entry.

https://python-reference.readthedocs.io/en/latest/docs/str/startswith.html

If you want to search for a partial match anywhere in the string you should look at using "in" (if substring in string). in will find strings that contain the string in entry. Neither of these do anything to find the "closest match". If it is important to do that, you should look at difflib.

https://docs.python.org/3/library/difflib.html

PROBLEM 2:
The posted code would match a complete entry, but the bind() is messed up. "<<KeyRelease>>" is not a valid event. I think you mean "<KeyRelease>".

When trying something new, I write little experiment programs. It lets me focus on few things and not have to worry about integrating the new feature into my program. These little programs are also quite useful when asking questions on the forum. If I was testing out this keybinding thing I would write a program like this:
import tkinter as tk

root = tk.Tk()
entry = tk.Entry(root, width=30)
entry.bind("<<KeyRelease>>", lambda event: print(entry.get()))
entry.pack()
root.mainloop()
Running the program I would see there is nothing getting printed when I type in the entry box. Now I know the problem is with getting events from the entry. This is a much smaller problem than I had before. If you had done this I bet it would've led you to research what events you can bind, and you would've noticed the KeyRelease event is surounded by <>, not <<>>.

PROBLEM 3:
I think binding KeyRelease is the wrong approach. Sure it will work for typing, but what about cut and paste? Instead of binding the keyboard, you should create a StringVariable and trace() changes to the string variable. This will report any change to the text in the entry, and that is what you really want.
import tkinter as tk

root = tk.Tk()
var = tk.StringVar()
entry = tk.Entry(root, textvariable=var, width=30)
var.trace("w", callback=lambda a, b, c: print(var.get()))
entry.pack()
root.mainloop()
Here's an example that prints the word that best matches the entry (according to difflab.SequenceMatcher).
import tkinter as tk
import re
from difflib import SequenceMatcher


def match(text):
    text = text.lower()
    matches = [(SequenceMatcher(None, text, word).ratio(), word) for word in words]
    print(max(matches)[1])


with open(__file__, "r") as file:
    words = {word.lower() for word in re.split("\W+", file.read())}

root = tk.Tk()
var = tk.StringVar()
tk.Entry(root, textvariable=var, width=30).pack()
var.trace("w", callback=lambda a, b, c: match(var.get()))
root.mainloop()
You should play with startswith(), "in" and difflib to see which you like the most.


RE: Search data in treeview without search button - TomasSanchexx - Aug-12-2023

(Aug-11-2023, 12:38 PM)TomasSanchexx Wrote: Hello,
I'm trying to make an item search engine in a treeview, if I do it with a button, it works for me.
But I want to do the search without a button, just writing in the entry I select the closest thing.
I have done this, it does not give me any errors or anything, but it does not select any similar item or anything.

self.entry_buscador = tk.Entry()
        self.entry_buscador.place(x=150, y=142, width=450, height=40)
self.entry_buscador.bind("<<KeyRelease>>", self.buscar)
def buscar(self, event):
        self.query = self.entry_buscador.get().lower()

        for item in self.treeview_almacen.get_children():
            values = self.treeview_almacen.item(item, "values")
            if self.query in values[0].lower():
                self.treeview_almacen.selection_set(item)
                self.treeview_almacen.focus(item)
                self.treeview_almacen.see(item)
            else:
                self.treeview_almacen.selection_remove(item)
what do i have wrong? what can i do


Thank you very much, yes it works correctly.

solution:
self.entry_finder.bind("<KeyRelease>", self.find)



RE: Search data in treeview without search button - deanhystad - Aug-12-2023

I really think using KeyRelease is a mistake.