OOP class struggles: treeview envoce gui refresh outside class ListView()

Dear Developpers,

the last days have been enlightening for me because I am getting more comfortable with this class thing 😉 Nevertheless beginner ??? are bound to happen ...

I have running plugin with a c4d.gui.TreeViewFunctions
in there def Select from which I would like to triger a GUI refresh inside the class TestDialog(c4d.gui.GeDialog): and therefore outside the class ListView(c4d.gui.TreeViewFunctions):

The manual calculation of the sum with self._CalcSum() works (by pressing a button) but I would like to have it interactive when the user selects something in the treeview.

I do not expext you to go through all my code a nice easy example would do I guess.

2021-02-07-Window_000014.png

All the code should work besides some not usefull bookmarks 😉

import c4d, os
from c4d import gui

# Be sure to use a unique ID obtained from http://www.plugincafe.com/.
PLUGIN_ID = 1000011 # TEST ID ONLY
PLUGIN_NAME = "Cad File Importer"
#TreeView Column IDs.
ID_CHECKBOX = 1
ID_NAME = 2
ID_OTHER = 3

ID_BOOKMARKLIST = ("C:\\Users\\admin\\Pictures", "E:\Bilder\Bilder Temp\Screenshots", "", "C:\\wrong path", "C:\\")

ID_FOLDERSELECTION_SYSTEM = 1111
ID_SCANCONTENT = 1112
ID_PATHSTRING = 1113
ID_INFOBOX = 201
ID_CLOSE = 1114
ID_SELECTALL = 1115
ID_SUMBOX = 1116
ID_COLOREDBORDER = 1117
ID_IMPORT = 1118

class TextureObject(object):
    """
    Class which represent a texture, aka an Item in our list
    """
    texturePath = "TexPath"
    otherData = "OtherData "
    _selected = False
    #filesize = 0

    def __init__(self, texturePath, otherData):
        self.texturePath = texturePath
        self.otherData = otherData
        #self.otherData = round(float(otherData) / 1024.0 / 1024.0, 1)
        #self.filesize = filesize

    @property
    def IsSelected(self):
        return self._selected

    def Select(self):
        self._selected = True

    def Deselect(self):
        self._selected = False

    def __repr__(self):
        return str(self)

    def __str__(self):
        return self.texturePath
        
    def NiceFileSize(self):
        return round(float(self.otherData) / 1024.0 / 1024.0, 1)
    
    
class ListView(c4d.gui.TreeViewFunctions):

    def __init__(self):
        self.listOfTexture = list() # Store all objects we need to display in this list
    
    """
    def _CalcSum(self):
        sumselected = 0
        
        for fileitem in self.listOfTexture:
            if fileitem.IsSelected == True:
                sumselected += fileitem.otherData
        
        print (round(float(sumselected) / 1024.0 / 1024.0, 1))
        return (round(float(sumselected) / 1024.0 / 1024.0, 1))
    """
    
    def IsResizeColAllowed(self, root, userdata, lColID):
        return True

    def IsTristate(self, root, userdata):
        return False

    def GetColumnWidth(self, root, userdata, obj, col, area):
        return 80  # All have the same initial width

    def IsMoveColAllowed(self, root, userdata, lColID):
        # The user is allowed to move all columns.
        # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
        return True

    def GetFirst(self, root, userdata):
        """
        Return the first element in the hierarchy, or None if there is no element.
        """
        rValue = None if not self.listOfTexture else self.listOfTexture[0]
        return rValue

    def GetDown(self, root, userdata, obj):
        """
        Return a child of a node, since we only want a list, we return None everytime
        """
        return None

    def GetNext(self, root, userdata, obj):
        """
        Returns the next Object to display after arg:'obj'
        """
        rValue = None
        currentObjIndex = self.listOfTexture.index(obj)
        nextIndex = currentObjIndex + 1
        if nextIndex < len(self.listOfTexture):
            rValue = self.listOfTexture[nextIndex]

        return rValue

    def GetPred(self, root, userdata, obj):
        """
        Returns the previous Object to display before arg:'obj'
        """
        rValue = None
        currentObjIndex = self.listOfTexture.index(obj)
        predIndex = currentObjIndex - 1
        if 0 <= predIndex < len(self.listOfTexture):
            rValue = self.listOfTexture[predIndex]

        return rValue

    def GetId(self, root, userdata, obj):
        """
        Return a unique ID for the element in the TreeView.
        """
        return hash(obj)

    def Select(self, root, userdata, obj, mode):
        """
        Called when the user selects an element.
        """
        if mode == c4d.SELECTION_NEW:
            # for tex in self.listOfTexture:
                # tex.Deselect()
            obj.Select()
        elif mode == c4d.SELECTION_ADD:
            obj.Select()
        elif mode == c4d.SELECTION_SUB:
            obj.Deselect()

        
        # i want to call _CalcSum here how ??? ------------------------------------------------------------------------------------------------------------------------------
        """
            MenuCommand ok
                dialog 
                    RestoreLayout
                        TestDialog ok
        """
        #sum = MenuCommand.dialog.RestoreLayout.TestDialog._CalcSum
        print (TestDialog._CalcSum)
        

    def IsSelected(self, root, userdata, obj):
        """
        Returns: True if *obj* is selected, False if not.
        """
        return obj.IsSelected

    def SetCheck(self, root, userdata, obj, column, checked, msg):
        """
        Called when the user clicks on a checkbox for an object in a
        `c4d.LV_CHECKBOX` column.
        """
        if checked:
            obj.Select()
        else:
            obj.Deselect()

    def IsChecked(self, root, userdata, obj, column):
        """
        Returns: (int): Status of the checkbox in the specified *column* for *obj*.
        """
        if obj.IsSelected:
            return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
        else:
            return c4d.LV_CHECKBOX_ENABLED

    def GetName(self, root, userdata, obj):
        """
        Returns the name to display for arg:'obj', only called for column of type LV_TREE
        """
        return str(obj) # Or obj.texturePath

    def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor):
        """
        Draw into a Cell, only called for column of type LV_USER
        """
        if col == ID_OTHER:
            #name = obj.otherData
            name = obj.NiceFileSize()
            geUserArea = drawinfo["frame"]
            w = geUserArea.DrawGetTextWidth(name)
            h = geUserArea.DrawGetFontHeight()
            xpos = drawinfo["xpos"]
            ypos = drawinfo["ypos"] + drawinfo["height"]
            drawinfo["frame"].DrawText(name, xpos, ypos - h * 1.1)

    def DoubleClick(self, root, userdata, obj, col, mouseinfo):
        """
        Called when the user double-clicks on an entry in the TreeView.

        Returns:
          (bool): True if the double-click was handled, False if the
            default action should kick in. The default action will invoke
            the rename procedure for the object, causing `SetName()` to be
            called.
        """
        #c4d.gui.MessageDialog("You clicked on " + str(obj))
        return True

    def DeletePressed(self, root, userdata):        
        "Called when a delete event is received."
        for tex in reversed(self.listOfTexture):
            if tex.IsSelected:
                self.listOfTexture.remove(tex)
        

class TestDialog(c4d.gui.GeDialog):
    _treegui = None # Our CustomGui TreeView
    _listView = ListView() # Our Instance of c4d.gui.TreeViewFunctions
    
    
    def CreateLayout(self):
        #create the menu
        self.MenuFlushAll()
        #Bookmarks menu
        self.MenuSubBegin("Bookmarks")
        #self.MenuAddString(MNU_BOOKMARK_1["id"], MNU_BOOKMARK_1["name"])
        #self.MenuAddString(MNU_BOOKMARK_2["id"], MNU_BOOKMARK_2["name"])
        
        for addid, folderlink in enumerate(ID_BOOKMARKLIST):
            self.MenuAddString(addid+500, folderlink) # we add 500 to be out of range of common IDs we subtract 500 below in the comand section
        self.MenuSubEnd()    

        if self.GroupBegin(id=1, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=5, cols=1, groupflags=c4d.BORDER_GROUP_IN):
            self.GroupBorderSpace(5, 5, 5, 5)
            self.GroupBorderNoTitle(borderstyle=c4d.BORDER_BLACK)

            # Folder Selection group with title
            #----------------------------------------------------------
            if self.GroupBegin(id=11, flags=c4d.BFH_SCALEFIT, rows=1, cols=1, title="Folderpath", groupflags=c4d.BORDER_GROUP_IN):
                self.GroupBorderSpace(5, 5, 5, 5)
                self.GroupBorder(c4d.BORDER_ROUND)
                
                # Colored Border group
                #----------------------------------------------------------
                if self.GroupBegin(id=ID_COLOREDBORDER, flags=c4d.BFH_SCALEFIT, rows=1, cols=3, groupflags=c4d.BORDER_GROUP_OUT):
                    self.GroupBorderNoTitle(c4d.BORDER_ACTIVE_2)
                    self.AddEditText(id=ID_PATHSTRING, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=432, inith=0, editflags=c4d.EDITTEXT_HELPTEXT)
                    self.SetString(id=ID_PATHSTRING, value="Choose folder with dialog or paste the path here.", flags=c4d.EDITTEXT_HELPTEXT )
                    self.AddButton(id=ID_FOLDERSELECTION_SYSTEM, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Select Folder")
                    self.AddButton(id=ID_SCANCONTENT, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Load folder content")
                    self.GroupEnd()            
                self.GroupEnd()
                
        if self.GroupBegin(ID_INFOBOX, cols=1, flags=c4d.BFH_SCALEFIT, initw=0, inith=0 ,title=""):
            self.AddStaticText(212, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name="Info box")
            self.GroupEnd()

        if self.GroupBegin(999, cols=1, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, initw=0, inith=0 ,title="Files in Folder:"):
            self.GroupBorderSpace(5, 5, 5, 5)
            self.GroupBorder(c4d.BORDER_ROUND) 
            
            self.AddCheckbox( ID_SELECTALL, flags=c4d.BFH_LEFT, initw=0, inith=0 , name="Select All")
            
            # Create the TreeView GUI.
            #----------------------------------------------------------
            customgui = c4d.BaseContainer()
            #customgui.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN )
            customgui.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_NONE | c4d.BORDER_GROUP_IN)
            customgui.SetBool(c4d.TREEVIEW_HAS_HEADER, True) # True if the tree view may have a header line.
            customgui.SetBool(c4d.TREEVIEW_HIDE_LINES, True) # True if no lines should be drawn.
            customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, False) # True if the user can move the columns.
            customgui.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True) # True if the column width can be changed by the user.
            customgui.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True) # True if all lines have the same height.
            customgui.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True) # Alternate background per line.
            customgui.SetBool(c4d.TREEVIEW_CURSORKEYS, True) # True if cursor keys should be processed.
            customgui.SetBool(c4d.TREEVIEW_NOENTERRENAME, True) # Suppresses the rename popup when the user presses enter.
            customgui.SetBool(c4d.TREEVIEW_NO_DELETE, True) # Disable Delete Message Callback completely for backspace and delete.
            #customgui.SetBool(c4d.TREEVIEW_ADDROW, True) # Show an add new column row at the bottom of the list.
            
            self._treegui = self.AddCustomGui( 1000, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 400, 100, customgui) # minw, minh 
            if not self._treegui:
                print ("[ERROR]: Could not create TreeView")
                return False
        
            self.GroupEnd()

        if self.GroupBegin(ID_SUMBOX, cols=2, flags=c4d.BFH_SCALEFIT, initw=0, inith=0, title="Filesizesum:"):
            self.GroupBorderSpace(5, 5, 5, 5)
            self.GroupBorderNoTitle(borderstyle=c4d.BORDER_BLACK)
            self.AddStaticText(332, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name="Selected: ")
            self.AddStaticText(333, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_RIGHT | c4d.BFH_SCALE, initw=0, inith=0, name="Filesize Sum: ")
            self.GroupEnd()

        
        # OK Cancel
        #----------------------------------------------------------
        if self.GroupBegin(id=3, flags=c4d.BFV_BOTTOM | c4d.BFH_SCALEFIT, inith=25, rows=1, cols=2, title="", groupflags=c4d.BORDER_GROUP_IN):
            #self.GroupBorderSpace(5, 5, 5, 5)
            self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE) # BORDER_NONE BORDER_BLACK
            self.AddButton(ID_CLOSE, flags=c4d.BFH_LEFT | c4d.BFV_SCALEFIT | c4d.BFH_SCALE | c4d.BFV_BOTTOM, name="Close")
            self.AddButton(ID_IMPORT, flags=c4d.BFH_RIGHT | c4d.BFV_SCALEFIT | c4d.BFH_SCALE | c4d.BFV_BOTTOM, name="Import")
            self.GroupEnd()
        
        self.GroupEnd() # main group end
        
        # self.AddButton(1001, c4d.BFH_CENTER, name="Add")

        return True

    def InitValues(self):        
        self.folderpath = None
    
        # Initialize the column layout for the TreeView.
        layout = c4d.BaseContainer()
        layout.SetLong(ID_CHECKBOX, c4d.LV_CHECKBOX)
        layout.SetLong(ID_NAME, c4d.LV_TREE)
        layout.SetLong(ID_OTHER, c4d.LV_USER)
        self._treegui.SetLayout(3, layout)

        # Set the header titles.
        self._treegui.SetHeaderText(ID_CHECKBOX, "Check")
        self._treegui.SetHeaderText(ID_NAME, "File Name")
        self._treegui.SetHeaderText(ID_OTHER, "Filesize (MB)")
        self._treegui.Refresh()

        # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
        self._treegui.SetRoot(self._treegui, self._listView, None)
        return True

# Change GUI
# --------------------------------------------------------------------------------------------------------------------------
    def _DrawGroup(self):
        print ("_DrawGroup: ", self.folderpath)

        # Flush the content of the group that holds all ours SubDialogs
        self.LayoutFlushGroup(ID_COLOREDBORDER)        

        # new content
        if self.folderpath == None or self.folderpath == "":            
            self.GroupBorderNoTitle(c4d.BORDER_ACTIVE_4) # orange
            self.AddEditText(id=ID_PATHSTRING, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=432, inith=0, editflags=c4d.EDITTEXT_HELPTEXT)
            self.SetString(id=ID_PATHSTRING, value="Choose folder with dialog or paste the path here.", flags=c4d.EDITTEXT_HELPTEXT )
            self.AddButton(id=ID_FOLDERSELECTION_SYSTEM, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Select Folder")
            self.AddButton(id=ID_SCANCONTENT, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Load folder content")  
            
            self.LayoutFlushGroup(ID_INFOBOX)
            self.AddStaticText(212, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name = "Select a path.")

        
        elif not os.path.exists(self.folderpath):
            self.GroupBorderNoTitle(c4d.BORDER_ACTIVE_3) # red
            self.AddEditText(id=ID_PATHSTRING, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=432, inith=0, editflags=c4d.EDITTEXT_HELPTEXT)            
            self.SetString(id=ID_PATHSTRING, value=self.folderpath)
            self.AddButton(id=ID_FOLDERSELECTION_SYSTEM, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Select Folder")
            self.AddButton(id=ID_SCANCONTENT, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Load folder content")  

            self.LayoutFlushGroup(ID_INFOBOX)
            self.AddStaticText(212, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name = "Invalid path please check.")
            
        else:
            self.GroupBorderNoTitle(c4d.BORDER_ACTIVE_2)
            self.AddEditText(id=ID_PATHSTRING, flags=c4d.BFH_LEFT | c4d.BFH_SCALEFIT, initw=432, inith=0, editflags=c4d.EDITTEXT_HELPTEXT)            
            self.AddButton(id=ID_FOLDERSELECTION_SYSTEM, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Select Folder")
            self.AddButton(id=ID_SCANCONTENT, flags=c4d.BFV_FIT | c4d.BFH_FIT | c4d.BFH_RIGHT, name="Load folder content")  
            self.SetString(id=ID_PATHSTRING, value=self.folderpath) # flags=c4d.EDITTEXT_HELPTEXT            
            
            self.LayoutFlushGroup(ID_INFOBOX)
            self.AddStaticText(212, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name = "Good to go.")

        # Notifies the content of the Group has changed
        self.LayoutChanged(ID_INFOBOX)
        self.LayoutChanged(ID_COLOREDBORDER)
        
# -------------------------------------------------------------------------------------------------------------------------- 
    def _ShowSum(self, valuetodisplay=0, selected=0):
        print ("_ShowSum: ")        
        howmanyselected = "Selected: " + str(selected)
        valuetodisplay = "Filesize Sum:  " + str(valuetodisplay) + " MB"
        
        self.LayoutFlushGroup(ID_SUMBOX)

        self.GroupBorderSpace(5, 5, 5, 5)
        self.GroupBorderNoTitle(borderstyle=c4d.BORDER_BLACK)
        self.AddStaticText(332, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_CENTER | c4d.BFH_SCALE, initw=0, inith=0, name=howmanyselected)
        self.AddStaticText(333, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_RIGHT | c4d.BFH_SCALE, initw=0, inith=0, name=valuetodisplay)
        self.LayoutChanged(ID_SUMBOX)

    def _CalcSum(self):
        sumselected = 0
        selected = 0
        
        for fileitem in self._listView.listOfTexture:
            if fileitem.IsSelected == True:
                sumselected += fileitem.otherData
                selected += 1
        
        self._ShowSum((round(float(sumselected) / 1024.0 / 1024.0, 1)), selected)
        #return (round(float(sumselected) / 1024.0 / 1024.0, 1))
        
# --------------------------------------------------------------------------------------------------------------------------
    def loadfolder(self):
        self._listView.listOfTexture = list() # flush the list hence we want to load the content only once
    
        # Add data to our DataStructure (ListView)
        newID = len(self._listView.listOfTexture) 

        if self.folderpath != None and self.folderpath != ""  and os.path.exists(self.folderpath):                 
            filelist = os.listdir(self.folderpath.decode("utf-8", "strict"))
            filelist.sort()
            for fileid, img in enumerate ( filelist ):
                #print (img)
                img = img.encode("utf-8", "strict")
                #print (img)
                fullpath = self.folderpath + "\\" + img
                #print (fullpath)
                #texsize = round(float(os.path.getsize(fullpath)) / 1024.0 / 1024.0, 1)
                texsize = os.path.getsize(fullpath)
                #tex = TextureObject("T{}".format(newID + fileid))                
                tex = TextureObject(img.format(newID + fileid), texsize) # the object
                self._listView.listOfTexture.append(tex) # the big list
                
                #print (img)
        else:
            print (self.folderpath)

        # Refresh the TreeView
        self._treegui.Refresh()    
    
    
    def Command(self, id, msg):
    
        if id == ID_SELECTALL:
            print ("Checkbox Staus: ", self.GetBool(ID_SELECTALL))             

            if self.GetBool(ID_SELECTALL) == True:
                for fileitem in self._listView.listOfTexture:                    
                    fileitem.Select()
                    
            if self.GetBool(ID_SELECTALL) == False:
                for fileitem in self._listView.listOfTexture:                    
                    fileitem.Deselect()                

            self._treegui.Refresh() 
            return True
  
        if 500 <= id <= 550:            
            bigid = int(id-500)
            #print ("Dropdown ID: ", id, ID_BOOKMARKLIST[bigid])
            self.SetString(ID_PATHSTRING, ID_BOOKMARKLIST[bigid])
            self.folderpath = self.GetString(ID_PATHSTRING)
            self._DrawGroup()
            return True            
        
        if id == ID_FOLDERSELECTION_SYSTEM:            
            self.folderpath = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_ANYTHING, title='Choose a Folder with the 3D Data to import.', flags=c4d.FILESELECT_DIRECTORY, force_suffix='', def_path='', def_file='')
            self.SetString(ID_PATHSTRING, str(self.folderpath))
            self._DrawGroup()
            return True
            
        if id == ID_SCANCONTENT:
            self.folderpath = self.GetString(ID_PATHSTRING)
            self._DrawGroup()
            self.loadfolder()        

        if id == ID_CLOSE:
            self.Close()
            return True
        
        if id == ID_IMPORT:
            self._CalcSum()
            return True

        return True

    def CoreMessage(self, id, msg):  
    
        if id == c4d.EVMSG_CHANGE:
            print "Scene was Changed"

        return gui.GeDialog.CoreMessage(self, id, msg)

    def Message(self, id, msg):
    
        if c4d.gui.GetInputState(c4d.BFM_INPUT_KEYBOARD, c4d.KEY_ESC, msg):
            if msg[c4d.BFM_INPUT_VALUE]:
                #print ("ESC Pressed - closing window.")
                self.Close()
                return True
        return gui.GeDialog.Message(self, id, msg)

class MenuCommand(c4d.plugins.CommandData):    
    dialog = None        

    def Execute(self, doc):
        if self.dialog is None:
            self.dialog = TestDialog()
        return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaulth=200, defaultw=600)

    def RestoreLayout(self, sec_ref):
        if self.dialog is None:
            self.dialog = TestDialog()
        return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)

def main():    
    # Retrieves the icon path
    directory, _ = os.path.split(__file__)
    fn = os.path.join(directory, "res", "cadfile_importer_icon.tif")

    if os.path.isfile(fn) :
        # Creates a BaseBitmap
        bmp = c4d.bitmaps.BaseBitmap()
        if bmp is None:
            raise MemoryError("Failed to create a BaseBitmap.")

        # Init the BaseBitmap with the icon
        if bmp.InitWith(fn)[0] != c4d.IMAGERESULT_OK:
            #raise MemoryError("Failed to initialize the BaseBitmap.")
            print ("Failed to initialize the BaseBitmap.")
    else:
        print ("Bitmap not Found.", PLUGIN_NAME)
        bmp = None    
        
    try:
        c4d.plugins.RegisterCommandPlugin(  id=PLUGIN_ID, 
                                            str=PLUGIN_NAME,  
                                            info=0, 
                                            icon=bmp, 
                                            help="Lists files of a folder.", 
                                            dat=MenuCommand()
                                            )
    except ValueError:
        print ("Following Plugin could not be registered: ",  PLUGIN_NAME)

if __name__ == "__main__":
    c4d.CallCommand(13957) # clear concole
    main()

PS: I never know in which subforum to put these broad questions ...

kind regards mogh

userdata parameter of the TreeViewFunctions overidden methods can be anything, your dialog for example. 😉

hi,

you could also add your gedialog as a parameter when you create your treeviewfunctions

something like this.

import c4d
import os
import weakref


class Hierarchy(c4d.gui.TreeViewFunctions):

  def __init__(self, dlg):
    # Avoid a cyclic reference.
    self._dlg = weakref.ref(dlg)
    # add the code ...

# when you create an instance of your TreeViewFunctions
data_model = Hierarchy(self)

and in your select method you need to call the dialog function like so

self._dlg()._CalcSum()

Cheers,
Manuel

thank you for your help, I am trying to understand ...

am I right in the assumption that this is not "clean code" in a pythonic sense ?
kind regards