相当直截了当的问题,尽管我最好使用 Google-Fu,但我在这方面找不到任何东西。
我有一个使用 Tkinter Treeview 小部件作为表格的 Python 应用程序。这适用于我需要使用它的用途,但最终会在几棵树中出现几百个项目。
无论如何要使 Treeview 可搜索,只要 Tree 具有焦点,用户只需键入几个字符并突出显示第一个字母匹配(而不是在窗口中输入搜索模式的单独实体)?
相当直截了当的问题,尽管我最好使用 Google-Fu,但我在这方面找不到任何东西。
我有一个使用 Tkinter Treeview 小部件作为表格的 Python 应用程序。这适用于我需要使用它的用途,但最终会在几棵树中出现几百个项目。
无论如何要使 Treeview 可搜索,只要 Tree 具有焦点,用户只需键入几个字符并突出显示第一个字母匹配(而不是在窗口中输入搜索模式的单独实体)?
您正在寻找的功能并非开箱即用,但您可以轻松编写代码。
简而言之:子类 Treeview 小部件,当在您的小部件上按下一个键时,在右上角显示一个条目(允许您叠加小部件),完成后,删除该条目。
以下是一些片段:
实例化您的附加小部件和绑定。
class SearchableTreeview(ttk.Treeview):
def __init__(self, *args, **kwargs):
ttk.Treeview.__init__(self, *args, **kwargs)
#create the entry on init but does no show it
self._toSearch = tk.StringVar()
self.entry = tk.Entry(self, textvariable=self._toSearch)
self.bind("<KeyPress>", self._keyOnTree)
self._toSearch.trace_variable("w", self._search)
self.entry.bind("<Return>", self._hideEntry)
self.entry.bind("<Escape>", self._hideEntry)
当一个键被按下时,显示带有位置的条目。entry.place(relx=1, anchor=tk.NE)
将在右上角的树上方显示条目。如果按下的键是一个字母,则将该字母复制到条目中。将焦点设置在条目上,以便后续按键落在其中。
对称地,当在条目上按下 Escape 或 Return 时,刷新内容,隐藏条目 ( place_forget
),并将焦点设置到树(否则,即使不可见,条目也会保持焦点)。
def _keyOnTree(self, event):
self.entry.place(relx=1, anchor=tk.NE)
if event.char.isalpha():
self.entry.insert(tk.END, event.char)
self.entry.focus_set()
def _hideEntry(self, event):
self.entry.delete(0, tk.END)
self.entry.place_forget()
self.focus_set()
您可以按照您想要的方式自由搜索您的项目(深度或广度优先,匹配开始或完整字符串...)。这是一个重用A Rodas 的答案并忽略大小写的示例。
def _search(self, *args):
pattern = self._toSearch.get()
#avoid search on empty string
if len(pattern) > 0:
self.search(pattern)
def search(self, pattern, item=''):
children = self.get_children(item)
for child in children:
text = self.item(child, 'text')
if text.lower().startswith(pattern.lower()):
self.selection_set(child)
self.see(child)
return True
else:
res = self.search(pattern, child)
if res:
return True
您可以定义自己的递归方法在 Treeview 小部件中进行搜索,并selection_set
在其文本以条目内容开头时调用相应的子项:
import Tkinter as tk
import ttk
class App(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
self.entry = tk.Entry(self)
self.button = tk.Button(self, text='Search', command=self.search)
self.tree = ttk.Treeview(self)
# ...
def search(self, item=''):
children = self.tree.get_children(item)
for child in children:
text = self.tree.item(child, 'text')
if text.startswith(self.entry.get()):
self.tree.selection_set(child)
return True
else:
res = self.search(child)
if res:
return True
而且,对于那些想要基于 Tcl 的解决方案的人来说,这里有一个:
proc searchtree {} {
set children [.tree children {}]
foreach id $children {
set text [.tree item $id -text]
if {$text eq [.e get]} {
.tree selection set $id
} else {
set children [.tree children $id]
foreach id $children {
set text [.tree item $id -text]
if {$text eq [.e get]} {
.tree selection set $id
}
}
}
.tree see $id
}
}
pack [ttk::treeview .tree]
# Inserted at the root, program chooses id:
.tree insert {} end -id widgets -text "Widget Tour"
# Same thing, but inserted as first child:
.tree insert {} 0 -id gallery -text "Applications"
# Treeview chooses the id:
set id [.tree insert {} end -text "Tutorial"]
# Inserted underneath an existing node:
.tree insert widgets end -text "Canvas"
.tree insert $id end -text "Tree"
pack [button .b -text "Search" -command searchtree]
pack [entry .e ]