Tkinter Treeview для элементов Tarfile

У меня возникли проблемы с написанием функции, которая могла бы получить список элементов tarfile с помощью метода .getmembers() и поместить их в правильную древовидную структуру (файлы в папках и подпапках) в виджете Treeview. Я нашел сообщение, похожее на то, что я хотел: Tkinter: виджет Treeview, но я просто не мог получить он адаптирован для просмотра архивов.
Проблема с решением, на которое я ссылался, заключается в том, что оно использует os для обхода заданного каталога и вставки элементов в Treeview. Конечно, это не будет работать с tar-файлом, потому что это файл, а не папка, поэтому, когда я попытался изменить решение, я сохранил элементы tar-файла в списке и попытался передать его через функцию, но это просто не работает для меня.

По сути, мне нужна помощь в написании функции, которая принимает список имен каталогов и файлов и может вставлять родительские каталоги в корень дерева, а дочерние элементы — в содержащие их папки.

import os
import tkinter as tk
import tkinter.ttk as ttk
import tarfile

window = tk.Tk()
window.title("Testing")
window.geometry("500x500")

tree = ttk.Treeview(window)
tree.pack()
tree.heading('#0', text="Item")
tree.column('#0', width=495)

# Get TAR items
with tarfile.TarFile("testing.tar") as topen:
    tarlist = topen.getmembers()

# Get our first directory in the list and remove it from stack
for i in tarlist:
    if i.isdir() == True:
        start_node = i.name
        del tarlist[tarlist.index(i)]
        break

# Insert root folder
root_node = tree.insert('', 'end', text=start_node)

def insert():
    # Go through the rest of the member list and put the member in the proper place
    # within the tree structure

window.mainloop()


person Jimmy-John    schedule 19.12.2019    source источник
comment
у меня это просто не работает не могли бы вы добавить сюда свою функцию с ошибкой Traceback?   -  person FrainBr33z3    schedule 19.12.2019
comment
Что ж, если вам нужна обратная трассировка, я использовал предложенное ниже решение, и оно дало Item pylzma-master/pylzma-master/src уже существующий. Но я предполагаю, что вы говорите о том, что у меня было до того, как я спросил, что я не мог получить свое первоначальное лучшее решение, так как я не мог вернуться к нему с помощью Ctrl-Z. По сути, ошибки трассировки не было; Он просто отображал содержимое нежелательным образом. В моем первоначальном решении использовалась некоторая комбинация os.dirname, чтобы получить имя каталога элементов дерева и сравнить его с именем каталога элементов списка, чтобы определить, является ли он дочерним элементом, это было беспорядочно и бестолково.   -  person Jimmy-John    schedule 19.12.2019
comment
Также я понимаю, как я сформулировал свой вопрос, как сделать эту функцию для меня, но я трачу так много времени, пытаясь понять это с каждой функцией, которую я пишу, не давая мне желаемого результата. Выбор одного из них для моего примера кода будет трудным и просто добавит ненужную чепуху. Спасибо и хорошего дня!   -  person Jimmy-John    schedule 19.12.2019


Ответы (2)


Идея состоит в том, чтобы использовать полный путь элемента в качестве его идентификатора идентификатора в дереве, чтобы вы могли получить как родительский элемент, так и метку элемента с помощью parent, label = os.path.split(item.path).

Согласно .getmembers() docstring,

Возврат членов архива в виде списка объектов TarInfo. Список имеет тот же порядок, что и элементы в архиве.

Таким образом, вам не нужно беспокоиться о существовании родителя, он будет создан раньше, если вы пройдете tarlist с циклом for, как в приведенном ниже коде.

import os
import tkinter as tk
import tkinter.ttk as ttk
import tarfile

window = tk.Tk()
window.title("Testing")
window.geometry("500x500")

tree = ttk.Treeview(window)
tree.pack()
tree.heading('#0', text="Item")
tree.column('#0', width=495)

# Get TAR items
with tarfile.TarFile("testing.tar") as topen:
    tarlist = topen.getmembers()


def insert():
    for item in tarlist:
        parent, label = os.path.split(item.path)
        tree.insert(parent, 'end', iid=item.path, text=label)

insert()
window.mainloop()
person j_4321    schedule 19.12.2019
comment
Это работало до некоторой степени, но не могло отображать файлы, которые находились на базовом уровне Tarfile. Это должно быть потому, что я получаю сообщение об ошибке, которое мне нужно было отловить: Item pylzma-master/pylzma-master/src уже существует, поэтому я распечатаю список и найду причину ошибки, и я получу вернуться к вам. Это было намного проще, чем использовать os.dirname и извлекать имя с помощью tree.item('text') и смотреть, является ли элемент дочерним элементом. Спасибо. - person Jimmy-John; 19.12.2019
comment
Хорошо, только что провел некоторую исследовательскую работу, ошибка возникает из-за того, что есть копия указанного выше элемента, но потому что один из них является каталогом, а другой - файлом без расширения, но он обрабатывается как копия указанного каталога. Мне было интересно, можно ли это обойти, используя метод .isdir() из модуля tarfile? Чтобы определить, какой элемент является каталогом, а какой файлом, независимо от расширения/имени. - person Jimmy-John; 19.12.2019
comment
Я принимаю ваш ответ, так как именно вы помогли мне достичь моей цели, большое спасибо. Я также опубликовал ответ, показывающий, какие модификации я сделал, чтобы точно настроить его по своему вкусу и исключить любые аномалии. Еще раз большое спасибо и хорошего дня. - person Jimmy-John; 20.12.2019
comment
@ Джимми-Джон Спасибо, я рад, что смог помочь. - person j_4321; 20.12.2019

Благодаря j_4321, вот что я сделал, чтобы получить то, что хотел. Я разделил tarlist на список tardirs и tarfiles, а затем добавил сначала tardirs, так как хотел, чтобы они были упорядочены иерархически. Затем следовали tar-файлы, которые вставлялись на свое место. Я использовал обработчик исключений для обнаружения любых аномалий, когда файл имеет то же имя, что и каталог, и избегал использования iid в этом случае. Результатом является хорошо структурированное представление архива TAR, далее будет добавление значков папок рядом с элементами, идентифицированными как каталоги, и тем, что не будет выглядеть презентабельно.

tardirs = []
tarfiles = []

for i in tarlist:
    if i.isdir() == True:
        tardirs.append(i)
    else:
        tarfiles.append(i)

def insert():
    for item in tardirs:
        parent, label = os.path.split(item.path)
        try:
            tree.insert(parent, 'end', iid=item.path, text=label)
        except Exception:
            tree.insert(parent, 'end', text=label)
    for item in tarfiles:
        parent, label = os.path.split(item.path)
        try:
            tree.insert(parent, 'end', iid=item.path, text=label)
        except Exception:
            tree.insert(parent, 'end', text=label)
person Jimmy-John    schedule 20.12.2019
comment
Для значков это довольно просто, просто используйте опцию image при вставке элемента. - person j_4321; 20.12.2019