How is the structure manager working?
-
On 23/03/2013 at 16:16, xxxxxxxx wrote:
Hello everybody,
i think its a bit difficulte to explain what I want, but Ill try to do my best. I wrote a tagdata to be able to work with large data tables. The result of the the tagdata is the variable list_.
import os import sys import c4d from c4d import plugins, utils, bitmaps, gui import datetime # be sure to use a unique ID obtained from www.plugincafe.com PLUGIN_ID = 10000045 #TEST ID def ValInType(o_val) : val = o_val if "," in o_val: o_val = o_val.replace(",", ".") try: return float(o_val) except ValueError: return str(val) class PlgTAG(plugins.TagData) : list_ = [] def Init(self, node) : return True def Message(self, node, type, data) : if type==c4d.MSG_DESCRIPTION_COMMAND: if data['id'][0].id==10002: self.LoadList(node) self.GetVal(node) self.FillPorts(node) return True def LoadList(self, op) : try: txt = open(op[10001], 'r') except IOError: gui.MessageDialog("File is not readable.") return lns = txt.readlines() txt.close() self.list_ = [] self.lncnt = len(lns) ccnt = 0 for ln in lns: cols = ln.split(";") if ccnt < len(cols) : ccnt = len(cols) #Just to get the largest columne count for ii in range(len(lns)) : new_ln = [] cols = lns[ii][0:len(lns[ii])-1].split(";") for i in range(ccnt) : if i < len(cols) : new_ln.append(ValInType(cols[i])) else: new_ln.append("None") self.list_.append(new_ln) self.colcnt = ccnt return if __name__ == "__main__": dir, file = os.path.split(__file__) bmp = bitmaps.BaseBitmap() bmp.InitWith(os.path.join(dir, "res", "icon.tif")) plugins.RegisterTagPlugin(id=PLUGIN_ID, str="PlgTAG", g=PlgTAG, description="PlgTAG", icon=bmp, info=c4d.TAG_MULTIPLE|c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE)
Now Id like to visible list_ in a commanddata. I can get list_ from somewhere else with:
class GetValues(object) : def __init__(self, list_=None, lncnt = 0, colcnt = 0) : super(GetValues, self).__init__() self.list_ = list_ self.lncnt = lncnt self.colcnt = colcnt # tag is the tagdata list_obj = GetValues() tag.Message(10000045, list_obj) list_ = list_obj.list_ lncnt = list_obj.lncnt colcnt = list_obj.colcnt
(https://developers.maxon.net/forum/topic/7036/7946_how-to-get-a-variable-from-plugintag -> Thanks to littledevil and niklas)
The commanddata:
import c4d from c4d import bitmaps, gui, plugins, utils import collections, os PLUGIN_ID = 10000055 #TestID only!!!!!!!!!!!! class GetValues(object) : def __init__(self, list_=None, lncnt = 0, colcnt = 0) : super(GetValues, self).__init__() self.list_ = list_ self.lncnt = lncnt self.colcnt = colcnt class MyDialog(gui.GeDialog) : tag = None list_ = [] lncnt = 10 colcnt = 10 def CreateLayout(self) : ln = 0 col = 0 element = 0 cntr = 0 hole = (self.lncnt+1)*(self.colcnt+1) self.ScrollGroupBegin( id=0, flags=c4d.BFH_SCALEFIT|c4d.BFV_SCALEFIT, scrollflags=c4d.SCROLLGROUP_VERT | c4d.SCROLLGROUP_HORIZ, initw=300, inith=50 ) self.GroupBegin(id=1, flags=c4d.BFV_TOP|c4d.BFH_LEFT, title="", cols=self.colcnt+1) for i in range(self.lncnt+1) : for ii in range(self.colcnt+1) : cntr += 1 if i == 0: if ii == 0: self.AddStaticText(id=i+2, flags=c4d.BFH_LEFT, name="", borderstyle=c4d.BORDER_NONE) else: self.AddStaticText(id=i+2, flags=c4d.BFH_LEFT, initw=100, name=str(col), borderstyle=c4d.BORDER_THIN_OUT) col += 1 else: if ii == 0: self.AddStaticText(id=i+2, flags=c4d.BFH_LEFT, initw=100, name=str(ln), borderstyle=c4d.BORDER_THIN_OUT) ln += 1 else: a = int(float(element)/self.colcnt) b = element - (a*self.colcnt) self.AddStaticText(id=i+2, flags=c4d.BFH_LEFT, initw=100, name=str(self.list_[a][b]), borderstyle=c4d.BORDER_THIN_IN) element += 1 self.GroupEnd() self.GroupEnd() return True def Command(self, id, msg) : return True def CoreMessage(self,id,msg) : if id == c4d.EVMSG_CHANGE or id == 1970300003: activeTag = c4d.documents.GetActiveDocument().GetActiveTag() if self.tag != activeTag: if activeTag == None: self.list_ = [] self.lncnt = 0 self.colcnt = 0 elif activeTag.GetType() != 10000045: self.list_ = [] self.lncnt = 0 self.colcnt = 0 else: self.tag = activeTag list_obj = GetValues() self.tag.Message(10000045, list_obj) self.list_ = list_obj.list_ self.lncnt = list_obj.lncnt self.colcnt = list_obj.colcnt self.tag = activeTag self.LayoutFlushGroup(0) self.CreateLayout() self.InitValues() self.LayoutChanged(0) return True class Test(plugins.CommandData) : dialog = None def Execute(self, doc) : if self.dialog is None: self.dialog = MyDialog() return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=1, defaulth=1) def RestoreLayout(self, sec_ref) : if self.dialog is None: self.dialog = MyDialog() return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref) if __name__ == "__main__": bmp = bitmaps.BaseBitmap() dir, f = os.path.split(__file__) fn = os.path.join(dir, "res", "icon.tif") bmp.InitWith(fn) plugins.RegisterCommandPlugin(id=PLUGIN_ID, str="Test", info=0, help="Test", dat=Test(), icon=bmp)
If the active tag of the document is a TableTag, the commanddata shows the table. If not, the commendata is empty. If the active tag is changed from one TableTag to an other the commanddata is refreshing its one and the table of the new active TableTag is shown. So far, so good.
It works well, but this way simply takes to long for refreshing. I tested with 12.000 element (1000 line, 12 columnes, 1.8sec.) and 120.000 elements (10000 lines, 12columnes, more than 4min.).So my question is: How is the structure manager working? I think it is a commanddata, too. And it gets the information from the pointtag of the active object.
I hope I explained comprehensibly.
Thanks for help
Greetings
rown -
On 23/03/2013 at 16:50, xxxxxxxx wrote:
Hi rown,
just some points/thoughts:
- I don't see where you fill in the GetValues object you are passing to the tag's Message() method. Did I miss it?
- I recommend you to use symbols instead of integral numbers. Eg. PLUGIN_ID in place where 10000045 is used.
- If I understood you correctly: It is the dialog that changes, not the CommandData. Just to clear the missunderstandings here.
- You can not expect the same performance as the structure dialog. It is using an optimized GUI widget and is written in C++.
Best regards,
-Niklas -
On 23/03/2013 at 17:08, xxxxxxxx wrote:
your code isn't very well commented, so it is kind of hard to tell what does make
your code so slow. i guess there are multiple reasons, but a pretty obvious reason
is that you are adding each data element as a seperate dialog element, so that your
gedialog has to display and manage 120 000 (statictext) members.c4d managers are generally speaking pretty sealed and we do not have much access
to them. when you have to display more complex data structures the common approach
would be to create a ressource element which can display and manage this data on a
lower level. as we do neither have access to CustomDataType/CustumGuiData in python
nor we can use most of the existing CustomGui classes in python your best shot would
be a UserAera. either by drawing each element into the Userarea or by creating a
large string and then just draw this string.i think the structure manager uses a table to display its data and i think we cannot use
the table ressource element in python (not for sure, have never tested it). -
On 23/03/2013 at 17:16, xxxxxxxx wrote:
I agree with littledevil, a UserArea might be the best (but not most comfortable) choice. Just
make sure you're just drawing what needs to be displayed and not all 120k rows.. o_OBest,
Niklas -
On 23/03/2013 at 17:18, xxxxxxxx wrote:
Hey Niklas,
I don't see where you fill in the GetValues object you are passing to the tag's Message() method. Did I or did you miss it?
Im sorry, but I do not really understand your question. GetValues() is called from Coremessage.
I recommend you to use symbols instead of integral numbers. Eg. PLUGIN_ID in place where 10000045 is used.
Yes, you are right. But until now it is a quick and dirty code. I waned it working befor well-looking.
If I understood you correctly: It is the dialog that changes, not the CommandData. Just to clear the missunderstandings here.
Yes, of course, the dialog changes.
You can not expect the same performance as the structure dialog. It is using an optimized GUI widget and is written in C++.
Of course. But Im sure there is a faster solution. For example: If I create the dialoge in the tagdata and the commanddata is getting it from there, the dialog just has to be created one time. But I dont know how to let the commanddata know that something has changed.
-
On 23/03/2013 at 17:34, xxxxxxxx wrote:
just another note, while this would actually slow your code down, rather than speeding
it up, the whole problem REALLY needs more modularization on the data level, instead
of pushing arround a bunch of dicts, list and tupples. it would make it much easier to
understand the code and add things like caching and displaying data in an efficient way.about getvalues. i think the main missconeption here is that the name sounds and looks like
a static method, while it is actually a class. you even fall yourself for this trap as you are saying
'GetValues() is called from Coremessage.' -
On 23/03/2013 at 18:22, xxxxxxxx wrote:
about getvalues. i think the main missconeption here is that the name sounds and looks like
a static method, while it is actually a class. you even fall yourself for this trap as you are saying
'GetValues() is called from Coremessage.'You are right. I know that I rarly use the right terms. But I already have that problem in my mother tongue. Ill start working on it.
Im still not really sure to know what higher, lower or data level means. I should keep my eyes open for that. And I will take a look at UserArea.
Thanks you both
rown