GeDialog Inserting BitmapButtons [SOLVED]
-
On 12/01/2015 at 15:49, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 14
Platform: Mac ;
Language(s) : C++ ;---------
Hello, I've been working with some GeDialog plugins and was trying to come up with a way to load a series of images from a folder and display them as buttons that can be clicked to merge an associated C4D file into the scene.I've been using this code, inside of a loop, to load the images as BitmapButtonCustomGui, and then code in Command() for when they're pressed.
BitmapButtonCustomGui* myButton; BaseContainer bc; LONG bordertouse =0; bc.SetLong(BITMAPBUTTON_BORDER, bordertouse); bc.SetBool(BITMAPBUTTON_BUTTON, TRUE); bc.SetLong(BITMAPBUTTON_TOGGLE, TRUE); myButton = (BitmapButtonCustomGui* )AddCustomGui(currentlocation,CUSTOMGUI_BITMAPBUTTON,"MY BUTTON", 0L,0,0,bc); AutoAlloc<BaseBitmap> bb; Filename bg; bg = previewfolder+Filename("preview1.tif"); if (bb->Init(bg) != IMAGERESULT_OK) return TRUE; myButton->SetImage(bb, FALSE);
This doesn't seem the best way to do this though. It scales up pretty poorly with more buttons and doesn't seem overly clean. Is there a better way to load a series of images into buttons dynamically and faster?
Thanks for any help,
Dan -
On 13/01/2015 at 08:51, xxxxxxxx wrote:
Hi Dan,
can you further elaborate what you mean by "scales poorly" and "doesn't seem overly clean"?
You could do the loading of the images in a separate thread, but I'm not sure that's worth the m ore complicated implementation. Surely depends on your situation. -
On 26/01/2015 at 09:27, xxxxxxxx wrote:
Hello, sorry about the super late response, got pull into two more projects and I haven't had time to return to this until now.
I'll try to make more sense! By scaling poorly I mean that a hundred images loads quick enough, but a five hundred take more than five times as long, it doesn't seem very efficient. By clean I mean that loading hundreds of BitmapButtonCustomGui doesn't feel like the right thing to do. It's technically working, although only with a smaller number of buttons than I would like.
I've considered separate threads, seems better to be loading the images as time goes on rather than all at once. I'm not overly sure how to implement it though. Is there a better type to use to display a long series of click-able images?
-
On 26/01/2015 at 09:52, xxxxxxxx wrote:
I think threads are only worth the effort if you're planning to update the buttons asynchronously and display a proxy image while the actual image is being loaded. 90% of the time is probably IO time which won't get quicker with seperate threads.
If you can't optimize the images, for instance because you display them from a user folder, you would want to do it like that anyway.
-
On 28/01/2015 at 05:02, xxxxxxxx wrote:
Hi Dan,
in general I agree with Niklas, that the main time spent will be file I/O. If delayed loading in a thread will improve to the "fluffticity" of your dialog, depends heavily on what you are intending to do (general GUI design? update rate?) and the nature of your images (average size of the images (pixel- and byte-wise)? what data type? layers involved? resizing involved?). And so does the implementation...
Afterall nearly all icon buttons in C4D's GUI are done with the BitmapButton and in my personal layouts, I tend to have lots of toolbars (all in all some hundred buttons for sure) and I don't experience any performance issues.
Of course I won't deny, that the BitmapButton adds some overhead, but I doubt, this plays a major role compared to the file I/O.
And of course you always have the option to implement your own GeUserArea, if you feel, you can improve the performance with your own implementation.
-
On 28/01/2015 at 05:57, xxxxxxxx wrote:
One important thing to note with the Cinema 4D icons is that they're all contained in one image file.
If it's icons like that, you should make sure to load the only once, maybe even on Cinema 4D startup. -
On 28/01/2015 at 05:59, xxxxxxxx wrote:
Yep, which again points to file I/O as the bottle neck.
-
On 19/02/2015 at 11:46, xxxxxxxx wrote:
Thanks for all of the information, I was going to try getting it work via threading. This is the way I was thinking of doing it, is there a better way?
I'm going to start a thread in Message() and have that thread RegistorIcon(), and then once I have it confirmed that it's been loaded I can insert the BitmapButton and it will be quicker.
LONG MainDialog::Message(const BaseContainer &msg,BaseContainer &result) { switch (msg.GetId()) { case BFM_SCROLLGROUP_SCROLLED: { LONG x1,x2,y1,y2; GetVisibleArea(idScrollGroup, &x1, &y1, &x2, &y2); if(atTheBottom<y2)//at the bottom of the scrollgroup, which means load more images. { th.Start();//starts the thread and passes the folder it should load from with RegisterIcon() th.threadRunning = TRUE; th.currentpath = PathToImages; } } void MyThread::Main() { value = 0; while(threadRunning == TRUE) { for (LONG x =0; x<10; x++) { if(RegisterIcon(5000+x, Filename(currentpath)+Filename(LongToString(x))) { GePrint("Registered:" +LongToString(x) ); } else { GePrint("Didn't work:" + LongToString(x)); } } threadRunning = FALSE; //Terminate the thread } }
The thread works with registering icons in Command(), but not when called from Message(), every RegisterIcon() returns false. I'm not very familiar with threads so I could be doing plenty of stuff wrong. Any ideas?
Dan
-
On 23/02/2015 at 08:08, xxxxxxxx wrote:
Hi Dan,
I'm not sure, that calling RegisterIcon() (actually any of the Register...() functions) from a threaded context is a good idea.
Why use RegisterIcon() at all in this context? Can't you load the images straight into BaseBitmaps?And then I'd do the mechanic like so (just a suggestion) :
- on BFM_SCROLLGROUP_SCROLLED trigger your thread (and give it info, which images to load)
- Now, your thread(s) loads images in the background. As soon as its done, it sends a special message
- on reception of this message you update your BitmapButtons with the loaded images
-
On 11/03/2015 at 10:51, xxxxxxxx wrote:
Just want to check, if you have made any progress?