1

我正在使用 Tix 在 Python 中编写一个小程序,该程序构建并显示具有复选框功能的某些文件夹的树视图(只有其中包含某个 xml 文件的文件夹)。每个项目都是可以选择(选中)的文件夹或子文件夹。我为此使用了 CheckList 和 Hlist

基于这个答案:我设法用复选框显示了我想要的文件夹结构。

问题是,每当检查父项时,我都需要自动检查嵌套项,这样我就不需要遍历同一个父项下的每个项。我在使用 Tix 的文档时遇到了很多麻烦。

互联网上似乎存在关于对象和方法的相互矛盾的信息,并且它们往往因信息来源而异。我几乎可以肯定 Hlist 中没有内置功能可以启用此“自动检查”功能,因此如果我错了,请纠正我,我必须自己开发它。

对此有任何提示或想法吗?我将发布所涉及的代码片段和文件夹树视图

首先,我创建清单并找到我感兴趣的目录:

def startCheckList(self):

    self.cl = Tix.CheckList(self.testsFrame, browsecmd=self.selectItem, width=600, height=600)

    self.cl.hlist.configure(indent=20, pady=2, padx=2, bg='#eef4fa', relief=GROOVE, font=self.customFont)
    self.cl.pack()

    for root, dirs, files in os.walk(EA.TESTSFOLDER):
        for aFile in files:
            (fileName, extension) = os.path.splitext(aFile)
            if (fileName == EA.TESTNAME):
                self.testPaths.append(root)

获得文件夹列表后,我将关联的元素添加到要显示的 Hlist

def display_paths(self):

    for path in self.testPaths:
        L = []
        path2list(L, path)

        self.create_recursive(L)

    self.cl.autosetmode()

如果存在元素,我不会创建新条目

def create_recursive(self, list):
    path = '.'.join(list)

    if path:

        if self.cl.hlist.info_exists(path) == '1':
            pass

        elif self.cl.hlist.info_exists(path) == '0':

            if list:

                self.create_recursive(list[:-1])
                self.cl.hlist.add(path, text=list[-1])
                self.cl.setstatus(path, "off")

你将如何进行?

到目前为止的程序视图

4

3 回答 3

2

好的,因为我找不到任何内置方法,所以我编写了下一个代码:

def selectItem(self, item):

    if self.cl.getstatus(item) == 'on':
        self.autoCheckChildren(item, True)
    if self.cl.getstatus(item) == 'off':
        self.autoCheckChildren(item, False)


def autoCheckChildren(self, i_item, stat):
    item = i_item
    if stat:
        if self.cl.hlist.info_children(item):
            for child in self.cl.hlist.info_children(item):
                self.cl.setstatus(child, "on")
                self.autoCheckChildren(child, True)
    elif not stat:
        if self.cl.hlist.info_children(item):
            for child in self.cl.hlist.info_children(item):
                self.cl.setstatus(child, "off")
                self.autoCheckChildren(child, False)

其中 selectItem 是选中复选按钮时调用的函数。我再次使用递归,但这可能不是最好的解决方案。

Another thing that I found is that when selecting a checkbox (any one from the checklist) the associated function specified by browsecmd=function is always called twice. 我在某处读到这是因为按下和释放鼠标被视为两个事件。

这与 Tkinter 中的单个检查按钮的行为不同,其中关联的函数只调用一次。我不知道为什么会有这样的差异。这个函数只能调用一次吗?

于 2015-06-24T06:30:13.253 回答
1

我知道这是一个旧帖子,但是在为此苦苦挣扎了一段时间之后,我才想出了一个解决方案。

根据文档,多个事件的原因是browsecmd鼠标按钮按下、鼠标移动和鼠标按钮向上触发。所以它至少会被触发两次 - 鼠标按下和鼠标向上。

我已经通过将清单绑定到鼠标向上事件解决了这个问题,并使用一个回调设置一个变量来指示甚至已经收到鼠标向上。然后我的browsecmd函数可以检查这个变量的状态,如果是True,那么它继续(然后将变量设置为False再次)。如果是False,则忽略它,因为它不是鼠标向上事件。

以下是我的代码的相关部分。

def __init__(self):
    # Insert your own init code here
    self.clMouseUpEvent = False
def checkListClicked(self, event):
    self.clMmouseUpEvent = True
def browseEvent(self, itemID):
    if self.clMmouseUpEvent:
        if self.cl.getstatus(itemID) == 'off':
            status = 'on'
        else:
            status = 'off'
        self.setChildrenStatus(itemID, status)
        self.clMmouseUpEvent = False
def setChildrenStatus(self, itemID, status):
    self.cl.setstatus(itemID, status)
    for childID in self.cl.hlist.info_children(itemID):
        self.setChildrenStatus(childID, status)
def someFunction(self):
    # Insert your own Tix check list set up code here
    self.cl.hlist.config(bg='white', selectbackground='white', selectforeground='black', header=True, browsecmd=self.browseEvent)
    self.cl.hlist.bind("<ButtonRelease-1>", self.checkListClicked)

更新

我随后发现单击披露指示器也会触发checkListclicked功能设置clMouseUpEventTrue然后导致下一次单击实际复选框以处理鼠标按下和鼠标按下事件。

我现在修改了我的代码以将clMouseUpEvent变量设置为0代替Falsetime.time()代替True。然后在我的browseEvent而不是检查clMouseUpEvent == True它检查time.time() - self.clMouseUpEvent < 0.01. 现在这似乎工作正常。

于 2018-07-11T07:04:09.013 回答
0

我使用了与@Son of a Beach 类似的方法,但我也更改indicatorcmdhlist. CheckList每次按下指示器(折叠按钮)时都会运行此命令,并且覆盖它使其不再触发browsecmd.

这是代码:

        def toggle_path(tree: tix.CheckList, path: str):
            # delay clicks to not trigger it twice
            if time.time() - self._event_toggle > App.TOGGLE_EVENT_DELAY:
                getattr(tree, tree.getmode(path))(path)
            self._event_toggle = time.time()

        self.checklist = tix.CheckList(self.master,
                                      browsecmd=lambda path: self.select(self.checklist, path),
                                      command=lambda path: self.select(self.checklist, path))
        self.checklist.hlist.configure(indicatorcmd=lambda path: toggle_path(self.to_tree, path))

我希望这对将来使用它的人有任何帮助!

于 2020-06-29T12:25:58.533 回答