Как преобразовать список каталогов и файлов из обычного списка в древовидный список, используя python & PyQt5
Я использую Python и библиотеку PyQt5 для отображения списка каталогов и файлов, существующих по требуемому пути.
где пользователь выбирает нужную папку, а программа создает список, в котором хранятся все существующие папки, вложенные папки и файлы, затем он добавляет этот список в QlistWidget для отображения всех папок.
что я хочу, чтобы преобразовать этот список в TreeList, чтобы сделать отображение следующим образом:
folder1
subfolder1
file1
file2
folder2
subfolder1
file1
file2
file3
subfolder2
file1
функция:
def checkPath(self,folder):
fileList=[]
try:
directory=folder
'''
check if entered path exist
sleep for 2 seconds
'''
if os.path.exists(folder):
print("{0} is a valid Path".format(folder))
time.sleep(2)
self.listWidgetPDFlist.clear()
'''
looping over the path using os,walk
==> filter the PDF files then join the path entered with the fileName
==> append the filtered files into a list in order to apply list functions.
'''
for root,dirs,files in os.walk(directory):
for filename in files:
if filename.endswith(self.lineEdit_Ext.text()):
t=os.path.join(root,filename)
print(t)
fileList.append(t)
# add the list into the listWidgetPDFlist
self.listWidgetPDFlist.addItems(fileList)
# get the total number of existing PDF files in the requested path
totalPDFNum=len(fileList)
'''
check if the length of the list if <= 0
yes ==> no PDF files were founded TOTAL = 0
no ==> PDF files were founded TOTAL = totalPDFNum
'''
if(totalPDFNum <= 0 ):
print("{0} path doesn't includes any {1} files ".format(directory,self.lineEdit_Ext.text()))
self.lineEditTotalPDFnumber.setText(str(totalPDFNum))
else:
self.lineEditTotalPDFnumber.setText(str(totalPDFNum))
print ("\nthe ToTal Number of files = {0} ".format(totalPDFNum) )
return folder
#if entered path doesn't exist
else:
print("{0}is not a valid Path".format(folder))
return False
except Exception as e:
print("this error occure {0}".format(e))
2 ответа
Этот метод построит представление дерева рекурсивно.
def make_tree(self, folder): # folder here is a path to a folder
root = self.populate(folder)
self.tree_view.insertTopLevelItem(0, root)
def populate(self, path):
tree_item = QTreeWidgetItem()
tree_item.setText(0, os.path.basename(path))
for file in os.listdir(path):
if os.path.isdir(os.path.join(path, file)):
tree_item.addChild(self.populate(os.path.join(path, file)))
else:
sub_item = QTreeWidgetItem()
sub_item .setText(0, file)
tree_item.addChild(sub_item )
return tree_item
make_tree
Метод создает объект корневого каталога и устанавливает его как объект верхнего уровня дерева.
populate
Метод рекурсивно строит иерархию папок, создавая элемент дерева по указанному пути, а затем, если этот путь является каталогом, добавляя каждый дочерний элемент как дочерний элемент нового элемента дерева.
Будьте осторожны, какую папку вы установите в качестве корня этого метода, в результате вы можете получить много-много тысяч элементов дерева. Было бы хорошей идеей для реализации какого-либо ограничения глубины.
Я думаю, что то, что вам нужно, может быть легко достигнуто pathlib.Path.glob
чем os.walk, вместе с Path.parts вы можете собрать вложенный dict следующим образом:
from collections import defaultdict
from pathlib import Path
nested_dict = lambda: defaultdict(nested_dict)
def place_in_nested_dict(nested, place, value):
if isinstance(place, str):
place = [place]
place = list(place)
last = place.pop()
for node in reversed(place):
nested = nested[node]
nested[last] = value
def find_files(root=Path('.'), pattern='**/*.pdf'):
tree = nested_dict()
for file in root.glob(pattern):
if file.is_dir():
continue
parts = file.relative_to(root).parts
name = file.name
place_in_nested_dict(tree, parts, file.relative_to(root))
return tree
используйте это дерево, чтобы заполнить свой TreeWidget чем-то вроде этого:
def populate(tree: dict, root: Path):
tree_item = QTreeWidgetItem()
tree_item.setText(0, str(root))
for key, value in tree:
if isinstance(value, dict):
tree_item.addChild(populate(tree, key))
else:
tree_item.addChild(key)
return tree_item