Попытка разобрать CheckboxTreeview из ttkwidgets и получить статус флажка всех элементов в дереве - PullRequest
1 голос
/ 30 января 2020

Я пытался проанализировать древовидный список флажков, чтобы получить словарь с идентификатором элемента в качестве ключа и статусом флажка в качестве значений «флажок», «непроверенный» и «состояние tristate». Однако я попытался отсортировать элементы с помощью CheckboxTreview.get_checked (). Я не знаю, правильно ли я это использую или это просто недостаток пакета, но он возвращает только отмеченный элемент с самого высокого уровня ('' как родитель).

from tkinter import *
from tkinter import ttk
from ttkwidgets import CheckboxTreeview

def parse_Tree(tree, parent):

    children = list(tree.get_children(parent))
    checkedList = tree.get_checked()
    itemDic = {}
    #print(checkedList)

    for item in children:
        if tree.get_children(item) == () and item in checkedList:
            itemDic[item] = "checked"
        elif tree.get_children(item) != () and item in checkedList:
            itemDic[item] = "checked"
            itemDic.update(parse_Tree(tree, item))
        elif tree.get_children(item) != () and item not in checkedList:
            for boxStatus in parse_Tree(tree, item).values():
                if boxStatus == "checked" or boxStatus == "tristate":
                    itemDic[item] = "tristate"
                else:
                    itemDic[item] = "unchecked"
                    itemDic.update(parse_Tree(tree,item))
        else:
            itemDic[item] = "unchecked"

    return itemDic

def listTreeview(textFile):

    list = []
    file = open(textFile, "r")
    treeview = file.read().split("\n")
    file.close()
    for item in treeview:
        list += [item.split(",")]
    root = Tk()
    master = ''
    level = []
    tree = CheckboxTreeview(root)
    for index,i in enumerate(list):
        indent = 0

        while i[0][indent] == ' ': indent += 1

        if indent%4:
            print("wrong indentation")
            break
        else:
            i[0] = i[0].replace(' ','')

        level.append(int(indent/4))

        if len(level)==1:
            tree.insert(master,'end',i[0], text = i[0])
        elif level[index]-level[index-1] == 1:
            master = list[index - 1][0]
            tree.insert(master, 'end', i[0], text=i[0])
        elif level[index]-level[index-1] < 0:
            prev = index-1
            while level[index] != level[prev]:
                prev -= 1
            master = tree.parent(list[prev][0])
            tree.insert(master,'end',i[0], text = i[0])
        elif level[index] - level[index - 1] > 1:
            print('wrong indentation')
        else: #level hasnt change
            tree.insert(master, 'end', i[0], text=i[0])
        if i[1] == '1':
            tree.change_state(i[0], "checked")


    tree.expand_all()
    dic = parse_Tree(tree,'')
    print(dic)
    tree.pack()
    root.mainloop()

listTreeview("Treeview.txt")

I проанализировал следующий текстовый файл, чтобы работать с ним, отступ указывает уровень, а последнее число указывает, если он отмечен или нет. В этом примере, например, item4.1.1 должен выглядеть как item4.1.1: «флажок», но это не так ...

Есть ли еще какой-нибудь способ go через древовидный флажок и получить состояние каждого элемента?

item0,1
item1,0
    item1.1,0
    item1.2,0
item2,0
    item2.1,1
    item2.2,0
        item2.2.1,1
        item2.2.2,0
            item2.2.2.1,0
    item2.3,0
        item2.3.1,1
item3,1
item4,0
    item4.1,1
    item4.2,0
    item4.2.1,0

1 Ответ

1 голос
/ 04 февраля 2020

Причина, по которой tree.get_checked() не возвращает ожидаемый результат, заключается в том, что родительские элементы проверенных элементов нижнего уровня не проверены, и код предполагает, что все дочерние элементы не проверенного родительского элемента не проверены.

недостаток в виджете заключается в том, что он передает изменения состояния только по щелчку пользователя, например, если пользователь проверяет элемент, родительский элемент элемента становится либо проверенным, либо трехсторонним. Но этого не происходит, когда вы изменяете состояние элементов из кода.

Что вы можете сделать, это создать методы, которые проверяют / снимают отметку с элемента и распространяют изменение состояния:

from tkinter import Tk
from ttkwidgets import CheckboxTreeview as Tree


class CheckboxTreeview(Tree):

    def item_check(self, item):
        """Check item and propagate the state change to ancestors and descendants."""
        self._check_ancestor(item)
        self._check_descendant(item)

    def item_uncheck(self, item):
        """Uncheck item and propagate the state change to ancestors and descendants."""
        self._uncheck_descendant(item)
        self._uncheck_ancestor(item)

_(un)check_ancestor() и _(un)check_descendant() являются внутренними методами CheckboxTreeview, которые используются, когда пользователь нажимает на элемент.

Так что теперь, в listTreeview() вы можете использовать item_check() вместо change_state(), однако вам необходимо заменить

if i[1] == '1':
    tree.change_state(i[0], "checked")

на

if i[1] == '1':
    tree.item_check(i[0])
else:
    tree.item_uncheck(i[0])

, поскольку при проверке родительского элемента вновь созданного элемента по умолчанию также проверяется элемент.

Теперь у предков отмеченных элементов в вашем дереве есть правильное состояние, и поэтому tree.get_checked() вернет ожидаемый результат.

screenshot

Альтернатива: Если вы не хотите передавать состояния элементов их предкам и сохранять свое древовидное представление, как в вашем коде, вы можете рекурсивно искать проверенные элементы во всем дереве (и не только в том случае, когда предок проверен / сложен) :

def get_checked(tree):
    checked = []

    def rec_get_checked(item):
        if tree.tag_has('checked', item):
            checked.append(item)
        for ch in tree.get_children(item):
            rec_get_checked(ch)

    rec_get_checked('')
    return checked
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...