pythontkinterhlisttix

Autocheck children items in Tix with Python using CheckList and Hlist


I am writing a small program in Python using Tix that builds and displays a tree view of certain folders (only the ones having a certain xml file in them) with checkbox capabilities. Every Item is a folder or subfolder that can be selected (checked). I used CheckList and Hlist for this

Based on this answer: I managed to display the folder structure that I want with checkboxes.

The problem is that I need the nested Items to be autochecked whenever a parent is checked so that I do not need to go through every Item under the same parent Item. I am having a lot of trouble with the documentation with Tix.

There seems to be contradictory information on the internet about the objects and methods, and they are often different depending on the source of information. I am almost certain that there is not a built-in feature in Hlist that enables this "autocheck" function so correct me if I am wrong I would have to develop it myself.

Any hints or ideas on this? I will post the pieces of code involved and the folder treeview

First I create the Checklist and find the directories I am interested in:

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)

Once I have the folder list I add the associated elements to the Hlist to be displayed

def display_paths(self):

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

        self.create_recursive(L)

    self.cl.autosetmode()

If an element exists I do not create a new entry

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")

How would you proceed?

View of the program so far


Solution

  • I know this is an old post, but after struggling with this for a while, I've just come up with a solution.

    According to the documentation, the reason for multiple events is that the browsecmd is triggered for mouse button down, mouse moved and mouse button up. So it will be fired at least twice - for mouse down and mouse up.

    I've solved this problem by binding the checklist to the mouse up event, with a callback that sets a variable to indicate that a mouse up even has been received. My browsecmd function can then check the status of this variable, and if it is True, then it proceeds (AND THEN SETS THE VARIABLE TO False AGAIN). If it is False it ignores it because it is not a mouse up event.

    Below is the relevant part of my code.

    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)
    

    UPDATE:

    I subsequently found that clicking on the disclosure indicators also fired the checkListclicked function setting clMouseUpEvent to True which then resulted in the next click to an actual checkbox to process both the mouse down and mouse up events.

    I have now modified my code to set the clMouseUpEvent variable to 0 instead of False and time.time() instead of True. Then in my browseEvent instead of checking for clMouseUpEvent == True it checks for time.time() - self.clMouseUpEvent < 0.01. This seems to be working OK now.