在树视图中搜索并突出显示/选择包含搜索项目的行

时间:2017-09-12 12:15:05

标签: python search tkinter treeview tkinter-entry

我正在为患者的名单制作一个简单的GUI,其中包含患者的姓名和访问日期,使用tkinter和treeview,我有一个条目,用户应该输入患者姓名和想法如果患者的姓名位于列表中,则包含患者姓名的行(或行)将被突出显示(选中)。或者其他选项可以在所有患者的列表框中,仅显示我们搜索患者姓名的条目。

我之前没有使用过treeview,也找不到有关其功能和示例的大量数据,所以我在选择/突出显示部分时遇到困难,任何想法都会对此有所帮助....

到目前为止我的代码是:

import tkinter
from tkinter import ttk

class MainPage:

    def __init__(self,master):

        self.master = master
        self.frame = tkinter.Frame(self.master)
        self.master.columnconfigure(0, weight=1)
        self.master.columnconfigure(1, weight=3)
        self.master.columnconfigure(2, weight=1)
        self.master.columnconfigure(3, weight=1)
        self.master.columnconfigure(4, weight=1)

        self.searchfield = tkinter.Frame(self.master)
        self.searchfield.grid(row=1, column=0, columnspan=4)

        self.search_var = tkinter.StringVar()
        self.search_var.trace("w", lambda name, index, mode: self.selected)
        self.entry = tkinter.Entry(self.searchfield, 
                     textvariable=self.search_var, width=45)
        self.entry.grid(row=0, column=0, padx=10, pady=3)
        self.searchbtn = tkinter.Button(self.searchfield, text='Search', 
                         command=self.selected)
        self.searchbtn.grid(row=0, column=1)
        self.treeFrame = tkinter.Listbox(self.searchfield, width=45, height=45)
        self.treeFrame.grid(row=1, column=0, padx=10, pady=3)


        self.tree = ttk.Treeview( self.treeFrame, columns=('Name', 'Date'))
        self.tree.heading('#0', text='ID')
        self.tree.heading('#1', text='Name')
        self.tree.heading('#2', text='Date')
        self.tree.column('#1', stretch=tkinter.YES)
        self.tree.column('#2', stretch=tkinter.YES)
        self.tree.column('#0', stretch=tkinter.YES)
        self.tree.grid(row=4, columnspan=4, sticky='nsew')
        self.treeview = self.tree

        self.i = 1
        self.patient_list = [{"Name": "Jane", "Date": "05.09.2017"},
                             {"Name": "David", "Date": "04.09.2017"},
                             {"Name": "Patrick", "Date": "03.09.2017"}]
        for p in self.patient_list:
            self.tree.insert('', 'end', text="ID_"+str(self.i), values=
                             (p["Name"], p["Date"]))
            self.i = self.i + 1

        self.search_item = self.entry.get()
        for p in self.patient_list:
            if p["Name"] == self.search_item:
                self.selected(self.search_item)


    def selected(self):
        currentItem = self.tree.focus()
        print(self.tree.item(currentItem)['values'])


 root=tkinter.Tk()
 d=MainPage(root)
 root.mainloop()

提前致谢!

2 个答案:

答案 0 :(得分:1)

请参阅下面我解释的代码段:

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 = ["Jane", "Janet", "James", "Jamie"] #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()

因此,每次更新entry窗口小部件时,我们都会循环显示名称列表,并检查entry窗口小部件的值是否与element的值匹配names list直到entry小部件的值的长度(EG,如果我们输入一个五个字符长的字符串,那么我们检查该元素的前五个字符)。

如果匹配,则我们将树条目的id追加到list

检查完所有名称后,我们将匹配的list id传递给self.tree.selection_set(),然后突出显示所有匹配的树条目。

答案 1 :(得分:1)

某种搜索已经从框中实现,因此不需要另一种搜索!

您需要做的就是为患者提供合适的标签。之后,您可以通过这些标签搜索(是的,您可以向指定的患者提供多个标签)并控制患者的外观/突出显示(树视图行)。

让我们玩吧:

class MainPage:
    def __init__(self,master):
        #   ...
        for p in self.patient_list:
            #   Note tags argument, right now we use names of patients
            self.tree.insert('', 'end', text="ID_" + str(self.i), values=
                             (p["Name"], p["Date"]), tags=p["Name"])
        #   ...

    #   ...
    def selected(self):
        #   setting selection by iids with tag (name of a patient or whatever)
        self.tree.selection_set(self.tree.tag_has(self.search_var.get()))
    #   ...

现在这只是突出一位患者...... basic search ...但您可以使用.detach().move()对轻松修改此内容,以对整个树视图进行排序。

此外,您可以使用几行代码实现部分搜索

class MainPage:
    #   ...
    def selected(self):
        search_for = self.search_var.get()
        iid_to_select = ()

        #   if there's any sense in search
        if search_for != '':
            #   get all tags from tkinter
            all_tags = self.master.tk.call(str(self.tree), "tag", "names")

            #   sort tags by search query
            tags_to_select = tuple(filter(lambda tag: search_for.lower() in tag.lower(), all_tags))

            #   gather iids by tags to select
            for sorted_tag in tags_to_select:
                iid_to_select += self.tree.tag_has(sorted_tag)

        #   setting selection by iids
        self.tree.selection_set(iid_to_select)
    #   ...

partial search

总之,没有必要重新发明轮子,但如果你的树视图是用户可变的 - 请记住这些标签必须与可变内容同步。

有关树视图的更多信息,请here