Your browser does not seem to support JavaScript. As a result, your viewing experience will be diminished, and you have been placed in read-only mode.
Please download a browser that supports JavaScript, or enable it if it's disabled (i.e. NoScript).
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):
c4d.gui.TreeViewFunctions
def Select
class TestDialog(c4d.gui.GeDialog):
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.
self._CalcSum()
I do not expext you to go through all my code a nice easy example would do I guess.
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