I want to display a row that matches the entry from all of my entry boxes into the treeview. How can I get the values of the treeview and check if it matches the entry from one of the boxes and display the whole row. Here is my treeview code
tree = ttk.Treeview()
books_data = pandas.read_csv("List of Books - Sheet1 (3).csv")
df_column = books_data.columns.values
print(len(df_column))
print(df_column)
tree["column"] = list(books_data.columns)
tree["show"] = "headings"
for column in tree['column']:
tree.heading(column,text=column)
df_rows = books_data.to_numpy().tolist()
for row in df_rows:
tree.insert("","end",values=row)
tree.grid(column=0,row=4,columnspan=8)
CodePudding user response:
The short solution
import tkinter as tk
import tkinter.ttk as ttk
import sys
import pandas
# https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv
df = pandas.read_csv('./iris.csv')
df.head()
class main_window:
def __init__(self, root):
self.root = root
root.title("Treeview Search Example")
# INITIALIZE TREEVIEW SCROLLVIEW
self.tree = ttk.Treeview(root, columns=list(df.columns.values), show='headings')
self.tree.grid(row=1, column=0, sticky='nsew')
# https://stackoverflow.com/a/41880534/5210078
vsb = ttk.Scrollbar(root, orient="vertical", command=self.tree.yview)
vsb.grid(row=1, column=1, sticky='ns')
self.tree.configure(yscrollcommand=vsb.set)
for column in self.tree['column']:
self.tree.heading(column,text=column)
df_rows = df.to_numpy().tolist()
for row in df_rows:
self.tree.insert("","end",values=row)
# ADD SEARCH BOXES
search_frame = tk.Frame(root)
search_frame.grid(row=0, column=0, columnspan=2, sticky='nsew')
tk.Label(search_frame, text="sepal.length:").grid(row=0, column=0)
tk.Label(search_frame, text="sepal.width:").grid(row=0, column=2)
tk.Label(search_frame, text="petal.length:").grid(row=0, column=4)
tk.Label(search_frame, text="petal.width:").grid(row=0, column=6)
tk.Label(search_frame, text="variety:").grid(row=0, column=8)
# Add Search boxes
self.sepal_length_ent = tk.Entry(search_frame)
self.sepal_length_ent.grid(row=0, column=1)
self.sepal_width_ent = tk.Entry(search_frame)
self.sepal_width_ent.grid(row=0, column=3)
self.petal_length_ent = tk.Entry(search_frame)
self.petal_length_ent.grid(row=0, column=5)
self.petal_width_ent = tk.Entry(search_frame)
self.petal_width_ent.grid(row=0, column=7)
self.variety_ent = tk.Entry(search_frame)
self.variety_ent.grid(row=0, column=9)
tk.Button(search_frame, text="Search", command=self.search).grid(row=0, column=10)
def search(self):
# https://stackoverflow.com/a/27068344/5210078
self.tree.delete(*self.tree.get_children())
build_query = ""
# https://stackoverflow.com/a/56157729/5210078
if self.sepal_length_ent.get():
build_query = f'& {self.sepal_length_ent.get()} == `sepal.length` '
if self.sepal_width_ent.get():
build_query = f'& {self.sepal_width_ent.get()} == `sepal.width` '
if self.petal_length_ent.get():
build_query = f'& {self.petal_length_ent.get()} == `petal.length` '
if self.petal_width_ent.get():
build_query = f'& {self.petal_width_ent.get()} == `petal.width` '
if self.variety_ent.get():
build_query = f'& "{self.variety_ent.get()}" in `variety`'
if build_query:
print(build_query)
queried_df = df.query(build_query[1:])
else:
queried_df = df
df_rows = queried_df.to_numpy().tolist()
for row in df_rows:
self.tree.insert("","end",values=row)
if __name__ == '__main__':
main = tk.Tk()
main_window(main)
main.mainloop()
sys.exit()
The explanation of the solution
import tkinter as tk
import tkinter.ttk as ttk
import sys
import pandas
Obviously importing all the needed programs.
# https://gist.githubusercontent.com/netj/8836201/raw/6f9306ad21398ea43cba4f7d537619d0e07d5ae3/iris.csv
df = pandas.read_csv('./iris.csv')
df.head()
Loading the csv dataset. I used the IRIS dataset because it is easily accessible.
Jump ahead to:
if __name__ == '__main__':
main = tk.Tk()
main_window(main)
main.mainloop()
sys.exit()
Here we load the main_window
class into our main tkinter window (makes your code look neater)
The self-explanatory bit (added a ttk treeview with scrollbar):
class main_window:
def __init__(self, root):
self.root = root
root.title("Treeview Search Example")
# INITIALIZE TREEVIEW SCROLLVIEW
self.tree = ttk.Treeview(root, columns=list(df.columns.values), show='headings')
self.tree.grid(row=1, column=0, sticky='nsew')
# https://stackoverflow.com/a/41880534/5210078
vsb = ttk.Scrollbar(root, orient="vertical", command=self.tree.yview)
vsb.grid(row=1, column=1, sticky='ns')
self.tree.configure(yscrollcommand=vsb.set)
for column in self.tree['column']:
self.tree.heading(column,text=column)
df_rows = df.to_numpy().tolist()
for row in df_rows:
self.tree.insert("","end",values=row)
# ADD SEARCH BOXES
search_frame = tk.Frame(root)
search_frame.grid(row=0, column=0, columnspan=2, sticky='nsew')
tk.Label(search_frame, text="sepal.length:").grid(row=0, column=0)
tk.Label(search_frame, text="sepal.width:").grid(row=0, column=2)
tk.Label(search_frame, text="petal.length:").grid(row=0, column=4)
tk.Label(search_frame, text="petal.width:").grid(row=0, column=6)
tk.Label(search_frame, text="variety:").grid(row=0, column=8)
# Add Search boxes
self.sepal_length_ent = tk.Entry(search_frame)
self.sepal_length_ent.grid(row=0, column=1)
self.sepal_width_ent = tk.Entry(search_frame)
self.sepal_width_ent.grid(row=0, column=3)
self.petal_length_ent = tk.Entry(search_frame)
self.petal_length_ent.grid(row=0, column=5)
self.petal_width_ent = tk.Entry(search_frame)
self.petal_width_ent.grid(row=0, column=7)
self.variety_ent = tk.Entry(search_frame)
self.variety_ent.grid(row=0, column=9)
tk.Button(search_frame, text="Search", command=self.search).grid(row=0, column=10)
def search(self):
# https://stackoverflow.com/a/27068344/5210078
self.tree.delete(*self.tree.get_children())
Delete all the rows in the table
build_query = ""
# https://stackoverflow.com/a/56157729/5210078
if self.sepal_length_ent.get():
build_query = f'& {self.sepal_length_ent.get()} == `sepal.length` '
if self.sepal_width_ent.get():
build_query = f'& {self.sepal_width_ent.get()} == `sepal.width` '
if self.petal_length_ent.get():
build_query = f'& {self.petal_length_ent.get()} == `petal.length` '
if self.petal_width_ent.get():
build_query = f'& {self.petal_width_ent.get()} == `petal.width` '
if self.variety_ent.get():
build_query = f'& "{self.variety_ent.get()}" in `variety`'
Build a search query. Use ==
for integers/floats and use in
when searching inside strings. If you want to read more about queries, read this. If you wanted to do something wacky, like make one of your entries a "lower than" box for integers, you could even substitute in a <
or >
. It basically makes our life much easier here! Because we can do a query, based off a dynamically changing string!
if build_query:
print(build_query)
queried_df = df.query(build_query[1:])
else:
queried_df = df
If there is no build_query
(no inputs in entry boxes), just reload the table with the data from the df
. (if build_query:
is shorthand for if build_query != '':
)
If there is query data, do a query with the query terms.
df_rows = queried_df.to_numpy().tolist()
for row in df_rows:
self.tree.insert("","end",values=row)
Reload the treeview
with the data from the "new" queried df!
If you wanted a solution relate to your actual csv
and interface, I'd recommend sharing an example of your csv
and the gui design.
What the solution became
def search():
# clear the tree of data
tree.delete(*tree.get_children())
entries = [
title_entry,
author_entry,
subject_category_entry,
publication_date_entry
]
build_df = books_data
if entries[0].get():
build_df = build_df[build_df.TITLE.str.contains(entries[0].get())]
if entries[1].get():
build_df = build_df[build_df.AUTHOR.str.contains(entries[1].get())]
if entries[2].get():
build_df = build_df[build_df.SUBJECT_CATEGORY.str.contains(entries[2].get())]
if entries[3].get():
build_df = build_df[build_df.PUBLICATION_DATE == (entries[3].get())]
df_rows = build_df.to_numpy().tolist()
for row in df_rows:
tree.insert("","end",values=row)