在 tkinter 的分层树视图中递归排列所有文件夹和文件

Recursively arrange all folders and files in a hierarchical treeview in tkinter

我正在尝试在 tkinter 中创建一个资源管理器。我刚刚听说了分层 Treeview。因此,我正在尝试实现它。

在这里,我尝试使用递归,因为对于 for 循环,无法知道特定文件夹中的子目录和文件的数量。

这是我的递归函数。

def new_folder(path,arrs):

    for arr in arrs:
        if os.path.isdir(path+"\"+arr):
            try:
                a1=os.listdir(path+"\"+arr)
                new_folder(path+"\"+arr,a1)

            except PermissionError:
                pass
        else:
            print(path+"\"+arr)

path="C:\Users\91996\Documents"
arrss=os.listdir(path)
new_folder(path,arrss)

每当我 运行 这段代码时,它都会给我这个错误:

Traceback (most recent call last):
  File "c:/Users/91996/Documents/Visual studio code/focd.py", line 47, in <module>
    new_folder(path,arrss,'item'+str(2))
  File "c:/Users/91996/Documents/Visual studio code/focd.py", line 37, in new_folder
    new_folder(path+"\"+arr,a1,values[:-1]+str(3))
  File "c:/Users/91996/Documents/Visual studio code/focd.py", line 44, in new_folder
    treeview.move(values,'item1','end')
  File "C:\Program Files\Python3.8.6\lib\tkinter\ttk.py", line 1388, in move
    self.tk.call(self._w, "move", item, parent, index)
_tkinter.TclError: Item item3 not found

这是我的代码。

from tkinter import *
import os
# Importing ttk from tkinter
from tkinter import ttk

# Creating app window
app = Tk()

# Defining title of the app
app.title("GUI Application of Python")

# Defining label of the app and calling a geometry
# management method i.e, pack in order to organize
# widgets in form of blocks before locating them
# in the parent widget
ttk.Label(app, text ="Treeview(hierarchical)").pack()

# Creating treeview window
treeview = ttk.Treeview(app)

# Calling pack method on the treeview
treeview.pack()

# Inserting items to the treeview
# Inserting parent
treeview.insert('', '0', 'item1',
                text ='Documents')

# Inserting child
i=3
def new_folder(path,arrs,values):
    global i
    for arr in arrs:
        if os.path.isdir(path+"\"+arr):
            try:
                a1=os.listdir(path+"\"+arr)
                new_folder(path+"\"+arr,a1,values[:-1]+str(i))
                i+=1
            except PermissionError:
                pass
        else:
            treeview.insert(values,'end',text=arr)
            print(path+"\"+arr)
    treeview.move(values,'item1','end')
path="C:\Users\91996\Documents"
arrss=os.listdir(path)
new_folder(path,arrss,'item'+str(i))
app.mainloop()

目前,这是我使用 for 循环制作的 Treeview。但是,我觉得这不好,因为它不会获取文件和文件夹。我必须进行 8 次嵌套 for 循环才能将所有文件和文件夹获取到第 8 个子文件夹。但是递归可以解决所有问题。唯一的问题在于用 ttk.Treeview.

来实现它

您开始于:


i=3
...
new_folder(path,arrss,'item'+str(i))

如果将这些行添加到函数中,您将看到 item3 尚不存在。


def new_folder(path,arrs,values):
    print('item1 ->', treeview.exists('item1'), treeview.item('item1'))
    print(values, '->', treeview.exists(values))
    global i
    for arr in arrs:
        print(f"action: treeview.insert(values,'end',text=arr)")
        print(f"insert arguments: parent='{values}', index='end', text='{arr}'")

输出:


item1 -> True {'text': 'Documents', 'image': '', 'values': '', 'open': 0, 'tags': ''}
item3 -> False
action: treeview.insert(values,'end',text=arr)
insert arguments: parent='item3', index='end', text='file.ext'
Traceback (most recent call last):
...
    res = self.tk.call(self._w, "insert", parent, index, *opts)
_tkinter.TclError: Item item3 not found

您需要获取循环中所有找到的文件夹的 iid,并将它们用作当前父文件夹。


from tkinter import *
import os
from tkinter import ttk


app = Tk()
app.title("GUI Application of Python")

ttk.Label(app, text="Treeview(hierarchical)").pack()

treeview = ttk.Treeview(app, show='tree')
treeview.pack(fill='both', expand=True)


def new_folder(parent_path, directory_entries,
               parent_iid, f_image, d_image):
    """Creates a graphical representation of the structure
    of subdirectories and files in the specified parent_path.

    Recursive tree building for large directories can take some time.

    :param parent_path: directory path, string
    :param directory_entries: List[str]
           a list containing the names of the entries in the parent_path
           obtained using os.listdir()
    :param parent_iid: unique identifier for a treeview item, string
    :param f_image: file icon, tkinter.PhotoImage
    :param d_image: directory icon, tkinter.PhotoImage
    :return: None
    """
    for name in directory_entries:
        item_path = parent_path+os.sep+name
        # optional: file does not exist or broken symbolic link
        #if not os.path.exists(item_path):
            #print("Skipped:", item_path)
            #continue
        if os.path.isdir(item_path):
            # set subdirectory node
            subdir_iid = treeview.insert(parent=parent_iid,
                                         index='end',
                                         text=name,
                                         image=d_image)
            try:
                # pass the iid of the subdirectory as parent iid
                # all files/folders found in this subdirectory
                # will be attached to this subdirectory node
                subdir_entries = os.listdir(item_path)
                new_folder(parent_path=item_path,
                           directory_entries=subdir_entries,
                           parent_iid=subdir_iid,
                           f_image=f_image,
                           d_image=d_image)
            except PermissionError:
                pass
        else:
            treeview.insert(parent=parent_iid,
                            index='end',
                            text=name,
                            image=f_image)
        print(item_path)


# png 16x16 -> base64 strings for tkinter.PhotoImage
file_img = """
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdB
TUEAALGPC/xhBQAAAAlwSFlzAAAScwAAEnMBjCK5BwAAAalJREFU
OE99kUtLAmEUhg38Af6a6he06SJIF8FFREVtqkVEkBB2IcJIRDAk
80KrNq3CWihuuuh4GVIwM9BSa0bHUXGc8X7p1Bc6jtLLxzAwz3Pm
nPMNcaWySCR6CYVoOgMvzWaz3W63Wq1GowFPsVg8PDIqkUjg019A
gEOSJHAowEHAhDidzmAwGI3FEPZTXSDwafiJ3W5nWRbH8TSVGSAI
aBDi8TiGYT6fz2QyCwU+Dc0ADanX67XfWK3W/4QOjYRqtWqxWIQC
mhKh/NpAVyoVs/GcclwzabI7NF/odILocrnsPFwvGRcS6uUeob8T
RDOxMGuYz2vkfsdtVxhIg1AqMqnTRUYrD+iU2Vy+R+jvBMpTN+aC
Zi6umo2+RXouDmgkFJ4fyLNNNvUFdJFM0kfTuQOpfk9ZZLmuQBBE
Z4Np/VrtapVSKwqf7wmlLLc/iR9vGAyGnrWCgC4ImmZpKqVbKeoV
xK4sq5pI7kgjAfzCZBIK/PWX8jRxspRVjVPbY8FLLcdxfQKZ8vlx
j9eLebxuzOPGMO/j/YdyJro1dWezPblc4defieF8A+ZBma193+p6
AAAAAElFTkSuQmCC
"""
dir_img = """
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdB
TUEAALGPC/xhBQAAAAlwSFlzAAAScgAAEnIBXmVb4wAAAihJREFU
OE990vtv0kAcAPDh4wd/8w/yp5n4i4kkmizoBMKcRIfG7YepWSSZ
MSTGSXQao8wtjIw5ZkJEJ4+O0CGvoWhSCmw0sFJaHoU+GEJbyDax
EwMjQS+Xy30v97m7791JOF4Y+FMOBEJsj508PXD8lERyoj3Yp4ig
XclNRSlyg0F0TFxLRbXFyAMqaarkQrXabmfO4eqdoBRWtgQnujGM
+DRVbIYnTU3Wvrf7hcubGRToTOsFvK3V/JZyy6KeCXL7CZc3CEVj
k7bTO85/A+FDgwr6rKNIQEtu6XnC0Ch/+j+wCSXXulke994vxh/X
sNkGaaXTfXfYVLbEIwk2gbQBpstxz0QOmq6mdXxxmUr1A8Wg4i8o
rLoWh2C3hvhxr5KcqhMLVMrRJ4eCX97irL/qFh6fdxkvQoAaj4yz
iTv17KsyYu8D8t7hg+q7fXahjr50GaWQawT7OkbDN3/u6JIflQxb
qXN8zzsQniv7tGGv9Czx/tz64gXIqcTCagoaqWxpcO/dKBzL4oTI
uu+QBYaaBX2DeBgyDoJmKQzIMyEVE5Wz8HXMO7W29tnnD8TiiS5A
HbIGPi1kJn3zZzdWLh2CoIKGZHRUlXJPzs29XVoy40SuC6p0lgyo
+PS4e/aM8835GHALDWvY2LVybAxcVs881XtAUEyjC8SEGPx7bfu2
4/mgzfwiEgSz4dcJixRxjq5YVtEM1r6oHiDGuP9RwHS1TOaP/tCj
/d+VL1STn8NNZQAAAABJRU5ErkJggg==
"""
file_image = PhotoImage(data=file_img)
dir_image = PhotoImage(data=dir_img)

# adds a parent item to the tree
# and returns the item's iid value (generated automatically)
parent_iid = treeview.insert(parent='',
                             index='0',
                             text='Documents',
                             open=True,
                             image=dir_image)

start_path = os.path.expanduser(r"~\Documents")
start_dir_entries = os.listdir(start_path)

# inserting items to the treeview
new_folder(parent_path=start_path,
           directory_entries=start_dir_entries,
           parent_iid=parent_iid,
           f_image=file_image,
           d_image=dir_image)

app.mainloop()