使用 tkinter Treeview 小部件显示目录内容
Posted
技术标签:
【中文标题】使用 tkinter Treeview 小部件显示目录内容【英文标题】:Display directory content with tkinter Treeview widget 【发布时间】:2013-05-20 17:29:42 【问题描述】:目前我正在开发一个程序,该程序有自己的项目文件,内部就像子文件,我想知道如何使用树视图小部件来显示项目文件中的所有子文件,任何想法?
提前致谢!
【问题讨论】:
这个开源项目可能对你有很大帮助:github.com/talcs/tals_python_task_diary 【参考方案1】:有一个example in the source code of CPython 介绍了如何用目录的内容递归地填充 Treeview,这基本上就是它的工作原理(我已经删除了事件绑定并将其包装在一个类中以提高可读性):
import os
import tkinter as tk
import tkinter.ttk as ttk
class App(tk.Frame):
def __init__(self, master, path):
tk.Frame.__init__(self, master)
self.tree = ttk.Treeview(self)
ysb = ttk.Scrollbar(self, orient='vertical', command=self.tree.yview)
xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)
self.tree.heading('#0', text=path, anchor='w')
abspath = os.path.abspath(path)
root_node = self.tree.insert('', 'end', text=abspath, open=True)
self.process_directory(root_node, abspath)
self.tree.grid(row=0, column=0)
ysb.grid(row=0, column=1, sticky='ns')
xsb.grid(row=1, column=0, sticky='ew')
self.grid()
def process_directory(self, parent, path):
for p in os.listdir(path):
abspath = os.path.join(path, p)
isdir = os.path.isdir(abspath)
oid = self.tree.insert(parent, 'end', text=p, open=False)
if isdir:
self.process_directory(oid, abspath)
root = tk.Tk()
path_to_my_project = # ...
app = App(root, path=path_to_my_project)
app.mainloop()
更新:正如@ArtOfWarfare 提到的,可以使用<<TreeviewOpen>>
事件延迟填充树。为了模拟关闭的节点,我使用了一个空的子项,该子项会在打开目录时被移除:
import os
import tkinter as tk
import tkinter.ttk as ttk
class App(object):
def __init__(self, master, path):
self.nodes = dict()
frame = tk.Frame(master)
self.tree = ttk.Treeview(frame)
ysb = ttk.Scrollbar(frame, orient='vertical', command=self.tree.yview)
xsb = ttk.Scrollbar(frame, orient='horizontal', command=self.tree.xview)
self.tree.configure(yscroll=ysb.set, xscroll=xsb.set)
self.tree.heading('#0', text='Project tree', anchor='w')
self.tree.grid()
ysb.grid(row=0, column=1, sticky='ns')
xsb.grid(row=1, column=0, sticky='ew')
frame.grid()
abspath = os.path.abspath(path)
self.insert_node('', abspath, abspath)
self.tree.bind('<<TreeviewOpen>>', self.open_node)
def insert_node(self, parent, text, abspath):
node = self.tree.insert(parent, 'end', text=text, open=False)
if os.path.isdir(abspath):
self.nodes[node] = abspath
self.tree.insert(node, 'end')
def open_node(self, event):
node = self.tree.focus()
abspath = self.nodes.pop(node, None)
if abspath:
self.tree.delete(self.tree.get_children(node))
for p in os.listdir(abspath):
self.insert_node(node, p, os.path.join(abspath, p))
if __name__ == '__main__':
root = tk.Tk()
app = App(root, path='.')
root.mainloop()
【讨论】:
假设提问者真的在做文件系统的映射,这是一个很好的解决方案。 @DonalFellows - 无论提问者真正想做什么,这都是一个很好的答案,因为它确实回答了他们的问题。这正是我想要的(Treeview 的一个例子——我刚刚开始使用 tk/ttk,在我准备好自己从头开始编写东西之前需要查看更多示例。) 两年多过去了,我对此有了不同的想法——会不会真的效率低下?您将填充用户可能永远不会最终扩展的目录。当然有一种方法可以推迟调用process_directory
,直到用户真正打开它?
@ArtOfWarfare 当然有可能,请参阅我的更新答案。如果目录树很大,延迟加载可能是更好的解决方案 - 但是,该示例会变得更复杂一些 IMO。【参考方案2】:
支持 Python 3.4 及以上版本的第二行和第三行可以通过以下方式更改导入:
import tkinter as tk
import tkinter.ttk as ttk
tkinter 中的小写 t 替换了 Tkinter 中的大写 T,因为 Python 3.4 及更高版本不再识别 Tkinter;消除了“无法识别的参考”错误。
较新的 Python 版本中的完全限定导入指令对周围的点表示法更加严格,因此 tkinter.ttk as ttk 是必需的,并且消除了重复完全限定引用的需要。警告:人们会假设 import tk.ttk 就足够了,但不知何故会引发参考错误;消除过多的指针和条件宏处理使我选择了上述格式——还有其他可能性,但这是最容易使用的格式。
path_to_my_project = # ... 引发错误,但只是占位符(尽管仍然有效)并且可以更改为以下内容:
path_to_my_project = "" # ...
请记住,如果在 Windows 中运行脚本,使用反斜杠的文字文件路径会引发错误;您必须使用前面的反斜杠(双反斜杠)来转义文件路径 url 中的反斜杠,如下所示:
path_to_my_project = "C:\\Users\\userName\\Desktop\\projDir" #Windows file paths
使用反斜杠转义文件路径中的反斜杠消除了“Unicode 转义字符”错误,其中“C:\Users”解析为转义用户中的控制字符 U,这不是我们首先想要的。将路径转换为字符串将不起作用,因为会引发相同的错误,因此:
path_to_my_project = str("C:\Users\userName\Desktop\projDir")
...无效。
脚本示例(上面)适用于这些修改,针对在 Windows 10 64 位中运行的 Python 3.4 64 位,没有问题,并且非常干净和可靠。
我喜欢它——运行起来毫不费力(简单的更新),没有错误、警告或无法解释的变通办法、bs 和 hacks。竖起大拇指。
【讨论】:
不是答案,只是对上述实际答案的冗长评论。建议修改应在 cmets 中完成。以上是关于使用 tkinter Treeview 小部件显示目录内容的主要内容,如果未能解决你的问题,请参考以下文章
强制 Tkinter.ttk Treeview 小部件在缩小其列宽后调整大小
python 3 - tkinter - ttk treeview:查看列文本