【问题标题】:Error selecting mutliple items in python Tkinter Treeview在 python Tkinter Treeview 中选择多个项目时出错
【发布时间】:2018-10-11 21:24:05
【问题描述】:

我的应用程序中有一个可搜索的ttk.Treeview,它根据搜索词设置选择(突出显示)。

为此,我将要选择的项目收集到一个空格分隔的字符串中,如下所示:

"item_a item_b item_c"

我将此字符串传递给selection_set 方法。

我遇到的问题是,这在某些计算机上不起作用,尽管据我所知它们具有相同的 python 版本 (2.7.10)。

我收到如下错误消息:

"item_a item_b item_c": Item not found

好像它正在搜索具有那个巨大名称的一个项。

我可以通过创建一个列表并遍历它来实现相同的目标,对每个项目调用selection_add,但速度要慢得多。

我想可能是系统Tcl/Tk版本有差异,可能和python安装不一样,但我不确定,也不知道怎么验证。

但即使是这样,我也很难找到关于这方面的好的文档。在我找到的任何文档中都没有使用空格分隔字符串的想法,我刚刚在其他没有来源的 StackOverflow 帖子中看到了它。 (例如here

因此,我正在寻找与版本无关(或至少一种检测版本并执行不同操作的方法)的解决方案,以使用项目列表调用 selection_set。如果有人能告诉我如何做到这一点或指出可以帮助我理解如何做到这一点的文档,我将不胜感激。

【问题讨论】:

    标签: python tkinter treeview


    【解决方案1】:

    空格分隔的字符串起作用的原因是因为 tkinter 只是 tcl/tk 解释器的一个薄包装,并且 tcl 将接受空格分隔的字符串作为列表。 set_selection 接受一个列表作为参数,所以当你传递一个以空格分隔的字符串时,tcl 会根据其内部规则拆分字符串。

    调用set_selection 的正确方法是传递一个正确的python 列表,tkinter 会为您将其转换为一个tcl 列表。

    这是一个简短的示例,说明通过将包含三个元素的列表传递给 set_selection 来选择树中内容的子集:

    import tkinter as tk
    from tkinter import ttk
    
    root = tk.Tk()
    
    tree = ttk.Treeview(root)
    tree.pack(fill="both", expand=True)
    
    items = []
    for i in range(10):
        item = tree.insert("", "end", text="Item {}".format(i+1))
        items.append(item)
    
    items_to_select = items[2:5]
    tree.selection_set(items_to_select)
    
    root.mainloop()
    

    以上代码生成的窗口如下所示:

    【讨论】:

    • 感谢您的回复!这个答案听起来不错,我真的很欣赏这个例子,但这似乎对我不起作用。当我运行它时,我得到这个错误:TclError: Item [u'item_name', not found。当它被传递给tk.call 方法时,它几乎就像在items 上调用str() - 直到那时它绝对是一个列表,我的调试器不允许我更深入。
    【解决方案2】:

    要在 Python 2 中使用 selection_set,您需要传递一个项目元组来选择。您可以使用内置的tuple 函数轻松地将列表转换为元组。

    如果你可以升级到 Python 3,直接使用列表可能会更好。

    这是一个简单的测试程序,它使用几种不同的方法来选择 TreeView 中的项目。这应该适用于 Python 2 和 3,因此您可以查看哪些方法有效。

    try:
        import Tkinter as tk
        import ttk
    except ImportError:
        import tkinter as tk
        import tkinter.ttk as ttk
    import platform
    
    
    class TestWindow:
        def __init__(self):
            self.top = tk.Tk()
            self.top.title("Test TreeView selection")
            self.top.minsize(450, 600)
    
            self.root_frame = ttk.Frame(self.top, padding=5)
            self.root_frame.pack(fill=tk.BOTH, expand=True)
    
            self.python_version_label = ttk.Label(self.root_frame, text="Python Version: " + platform.python_version())
            self.python_version_label.pack(fill=tk.X, expand=False)
    
            self.version_label = ttk.Label(self.root_frame, text="TCL Version: " + tk.Tcl().eval('info patchlevel'))
            self.version_label.pack(fill=tk.X, expand=False)
    
            self.controls_frame = ttk.Frame(self.root_frame, padding=5)
            self.controls_frame.pack(fill=tk.X, expand=False)
    
            self.select_space_button = ttk.Button(self.controls_frame, text="Select Space", command=self.select_space)
            self.select_space_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
    
            self.select_loop_button = ttk.Button(self.controls_frame, text="Select Loop", command=self.select_loop)
            self.select_loop_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
    
            self.select_list_button = ttk.Button(self.controls_frame, text="Select List", command=self.select_list)
            self.select_list_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
    
            self.select_tuple_button = ttk.Button(self.controls_frame, text="Select Tuple", command=self.select_tuple)
            self.select_tuple_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
    
            self.clear_button = ttk.Button(self.controls_frame, text="Clear", command=self.clear)
            self.clear_button.pack(side=tk.LEFT, fill=tk.X, expand=True)
    
            self.tree_frame = ttk.Frame(self.root_frame, padding=5)
            self.tree_frame.pack(fill=tk.BOTH, expand=True)
    
            self.tree_view = ttk.Treeview(self.tree_frame, padding=5)
            self.ysb = ttk.Scrollbar(self.tree_frame, orient='vertical', command=self.tree_view.yview)
            self.tree_view.configure(yscroll=self.ysb.set)
    
            self.tree_view.pack(expand=True, fill=tk.BOTH, side=tk.LEFT)
            self.ysb.pack(side=tk.RIGHT, fill=tk.Y)
    
            self.tree_view.heading("#0", text="Test Item")
    
            for i in range(0, 100):
                name = "Item " + str(i)
                item_id = self.tree_view.insert("", tk.END, str(i), text=name, open=True)
                self.tree_view.insert(item_id, tk.END, str(i) + "a", text=name + ": A")
                self.tree_view.insert(item_id, tk.END, str(i) + "b",  text=name + ": B")
                self.tree_view.insert(item_id, tk.END, str(i) + "c",  text=name + ": C")
                self.tree_view.insert(item_id, tk.END, str(i) + "d",  text=name + ": D")
    
            self.items = []
            for i in range(4, 41):
                self.items.append(str(i))
                self.items.append(str(i) + "a")
                self.items.append(str(i) + "b")
                self.items.append(str(i) + "d")
    
        def select_space(self):
            self.tree_view.selection_set(" ".join(self.items))
    
        def select_loop(self):
            for item in self.items:
                self.tree_view.selection_add(item)
    
        def select_list(self):
            self.tree_view.selection_set(self.items)
    
        def select_tuple(self):
            self.tree_view.selection_set(tuple(self.items))
    
        def clear(self):
            self.tree_view.selection_remove(self.tree_view.selection())
    
        def run(self):
            self.top.mainloop()
    
    
    if __name__ == "__main__":
        window = TestWindow()
        window.run()
    

    我已经在 Windows 10、macOS 10.14 和 Debian Buster(Python 2 和 3)上对此进行了测试。“选择空间”在任何地方都不起作用,“选择循环”总是有效,但可能很慢,“选择列表” " 仅适用于 Python 3,并且 "Select Tuple" 始终有效。如果您被锁定到 2.7.10,这似乎是解决方案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-25
      • 2020-09-24
      • 2021-10-02
      • 2017-09-26
      • 1970-01-01
      • 2010-11-26
      • 2011-11-26
      相关资源
      最近更新 更多