4

相当直截了当的问题,尽管我最好使用 Google-Fu,但我在这方面找不到任何东西。

我有一个使用 Tkinter Treeview 小部件作为表格的 Python 应用程序。这适用于我需要使用它的用途,但最终会在几棵树中出现几百个项目。

无论如何要使 Treeview 可搜索,只要 Tree 具有焦点,用户只需键入几个字符并突出显示第一个字母匹配(而不是在窗口中输入搜索模式的单独实体)?

4

3 回答 3

6

您正在寻找的功能并非开箱即用,但您可以轻松编写代码。

简而言之:子类 Treeview 小部件,当在您的小部件上按下一个键时,在右上角显示一个条目(允许您叠加小部件),完成后,删除该条目。

以下是一些片段:

1) 子类化要扩展的小部件

实例化您的附加小部件和绑定。

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)

2) 临时入境

当一个键被按下时,显示带有位置的条目。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()

3) 实际搜索代码

您可以按照您想要的方式自由搜索您的项目(深度或广度优先,匹配开始或完整字符串...)。这是一个重用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
于 2013-06-24T08:58:37.230 回答
5

您可以定义自己的递归方法在 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
于 2013-06-22T08:49:40.457 回答
1

而且,对于那些想要基于 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 ]
于 2013-08-17T01:12:14.517 回答