Setting dialog fields from a thread



  • On 19/03/2014 at 02:57, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   R15 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    I have a command plugin with a dialog.
    In this dialog I start up another thread._<_o:_<_o:p_>_o:p>
    To monitor the progress, I want – in the thread – to update a slider in my dialog.
    Thus, I want to use – again in my thread – followi_<_o:_<_o:p_>_

      
    d = Float(pctDone) / 100.0;  
    msg.SetBool(BFM_STATUSBAR_PROGRESSON, TRUE);  
    msg.SetFloat(BFM_STATUSBAR_PROGRESS, d);  
    dlg->SendMessage(1002, msg);					//send message to dialog with progress info
    

    However, how to pass the dlg, the pointer to the dialog, to the thread?
    Here some snippets of the code

      
    class DownloadProgress : public CkHttpProgress
    {
    public:
             DownloadProgress(void);
             virtual ~DownloadProgress(void);
             void PercentDone(int pctDone, bool *abort);
    		 static Bool downloadAsynchrone(void);
    };
      
    void DownloadProgress::PercentDone(int pctDone, bool *abort)
    {
             BaseContainer msg(BFM_SETSTATUSBAR);
             Float d = Float(pctDone) / 100.0;
             msg.SetBool(BFM_STATUSBAR_PROGRESSON, TRUE);
             msg.SetFloat(BFM_STATUSBAR_PROGRESS, d);
             dlg->SendMessage(1002, msg);
             EventAdd(EVENT_FORCEREDRAW);
    }
      
    Bool DownloadProgress::downloadAsynchrone(void)
    {
        ....
        // start thread and monitor progress using DownloadProgress::PercentDone
        ...
    	return true;
    }
      
    class MainDialog : public GeDialog
    {
      
    public:
    	MainDialog(void);
    	virtual ~MainDialog(void);
      
    	virtual Bool CreateLayout(void);
    	virtual Bool InitValues(void);
    	virtual Bool Command(Int32 id, const BaseContainer& msg);
    	virtual Int32 Message(const BaseContainer& msg, BaseContainer& result);
    };
      
    Bool MainDialog::Command(Int32 id, const BaseContainer& msg)
    {
    	switch (id) 
    	{
    		case 1000:		//do command	
    		{
    		  DownloadProgress::downloadAsynchrone();
    		  break;
    		}
    	}
    	return true;
    }
      
        ...
      
    class MyPlugin : public CommandData
    {
    private:
    	MainDialog dlg;
      
    public:
      
    	//static MainDialog dlg;
      
    	virtual Bool Execute(BaseDocument* doc);
    	virtual Bool RestoreLayout(void* secret);
    };
      
    Bool MyPlugin::Execute(BaseDocument* doc)
    {
    	return dlg.Open(DLG_TYPE_ASYNC, ID_PIM, -1, -1); 
    }
      
    Bool MyPlugin::RestoreLayout(void* secret)
    {
    	return dlg.RestoreLayout(ID_PIM, 0, secret);
    }
      
    Bool RegisterMyPlugin(void)
    {
    	return RegisterCommandPlugin(ID_PIM, "Dialog - Threading", 0, AutoBitmap("icon.tif"), String("Chilkat Threading"), NewObjClear(MyPlugin));
    }
    

    Thanks to Steve for his previous help on the threading part.



  • On 19/03/2014 at 07:47, xxxxxxxx wrote:

    There's a threads example on my site that increments a text gizmo like a counter using a custom thread.
    Which should be easily changed to moving a slider with a minor code change.

    ThreadsExampleR12++
    https://sites.google.com/site/scottayersmedia/plugins

    -ScottA



  • On 19/03/2014 at 09:39, xxxxxxxx wrote:

    Yes and your example is working perfectly! Thanks.
    But it is very frustrating that I cannot get in to work in the way I describe.
    I know it must work, but I can't get it to work.

    Pim



  • On 19/03/2014 at 15:56, xxxxxxxx wrote:

    I haven't looked at Scotts example, but the usual way is to use SpecialEventAdd(), catch that message
    in the dialog, and instead of making the thread work on the dialog, let the dialog update the progress
    state itself by asking the thread.

    Calling SpecialEventAdd() is thread-safe.



  • On 20/03/2014 at 05:44, xxxxxxxx wrote:

    Scotts example is working real great, but I am trying to figure out other ways.

    At this moment I am using GeSyncMessage(pluginid, 9001, 9001, pctDone) and that is working great on Windows. However on Mac it seems as if the threat blocks cinema until down.
    After the thread finishes I receive ALL GeSyncMessage in one go.
    On windows the GeSyncMessage messages are received when the thread is running (not after as on the mac).

    I am going to try SpecialEventAdd().

    Pim



  • On 20/03/2014 at 08:05, xxxxxxxx wrote:

    OK, I tried the following:

    GeSyncMessage(EVMSG_ASYNCEDITORMOVE, 0, 9001, pctDone);
    Working under Windows. Messages are received while the tread is running
    Not working under Windows. Messages are NOT received while the tread is running. Only after the thread is stopped.

    Note: instead of EVMSG_ASYNCEDITORMOVE, I can also use the pluginid (ID_PIM)
    It is has not effect on the outcome. Windows ok, Mac not ok.

    SpecialEventAdd(ID_PIM, 9001, pctDone);
    Not working under Mac. Messages are NOT received while the tread is running. Only after the thread is stopped.
    Not working under Mac. Messages are NOT received while the tread is running. Only after the thread is stopped.



  • On 23/03/2014 at 20:37, xxxxxxxx wrote:

    I've made a quick test in Python, there is no difference regarding the implementation of
    SpecialEventAdd, it all goes through the place of the application.

    import c4d
    import time
    import threading
      
    PLUGIN_ID = 100234324
      
    class Dialog(c4d.gui.GeDialog) :
        
        def __init__(self) :
            super(Dialog, self).__init__()
            self.lock = threading.Lock()
            self.num = 0
      
        def Funk(self) :
            for i in xrange(10) :
                with self.lock:
                    self.num += 1
                c4d.SpecialEventAdd(PLUGIN_ID)
                time.sleep(0.3)
      
        def CreateLayout(self) :
            self.AddButton(1000, 0, name="Make Action!")
            self.AddStaticText(1001, 0, name="<empty>")
            return True
      
        def Command(self, param, msg) :
            if param == 1000:
                threading.Thread(target=self.Funk).start()
            return True
      
        def CoreMessage(self, id, msg) :
            if id == PLUGIN_ID:
                with self.lock:
                    self.SetString(1001, '***' * self.num)
                self.LayoutChanged(1001)
            return True
      
    dlg = Dialog()
    dlg.Open(c4d.DLG_TYPE_ASYNC)
    

    Works perfectly fine on Mac and Windows.
    Best,
    -Niklas


Log in to reply