[CONNECT C++] Wait for locate element command

I have have an application that creates its own dialog box, which is launched from my MDL application. I require functionality that the user locates an element in the DGN file and the control returns to this dialog box. I created a command in my MDL application to provide this functionality, but I need to "wait" for the user to either accept or reject the element before handing back the control.

I have attempted to solve this as follows:

Public int				g_zap_active = FALSE;

...

Private void zap_cleanup(WCharCP unused)
{
	g_zap_active = FALSE;

	...
}

Private void zap_start(
	WCharCP unparsedP)
{
	g_zap_active = TRUE;

	mdlState_startPrimitive(zap_datafunc, zap_start, COMMANDID_ZoomAndPick, 
		PROMPTID_identify_element);

	mdlLocate_init();
	mdlLocate_normal();
	mdlLocate_setCursor();

	StateCallback::SetCommandCleanupFunction(zap_cleanup);
}

Private int zoom_and_pick(
	...)
{
    ...
    
	zap_start(NULL);
	while (g_zap_active)
	{
		Sleep(1000);
	}

    ...
    
	return TRUE;
}

But this does not work because zoom_and_pick() needs to terminate for the command to even start.

My question is: what is the best way to solve this? I have thought about :

- Using CreateThread();

- Using Bentley::Tasks::TaskScheduler

But perhaps there is an easier way to accomplish this?

Parents
  • Hi Jan,

    Thank you for your reply.

    To explain the workflow: the user uses a button in the dialog box and then control passes to MicroStation to allow the user to locate an element or abandon the action. Then control returns to the dialog box. It is not the intention to open a dialog box from a command, but the opposite (launch a command from the dialog box). So what I need is a function in my MDL application which will return with the result of this command after the user has finished using it.

    So the question boils down to: Can I write a function (possibly by inheriting from the DgnElementSetTool class) that will start the command and not return a result until the user has either accepted an element or cancelled?

    Cheers,

    Mark.

  • Then control returns to the dialog box. It is not the intention to open a dialog box from a command, but the opposite (launch a command from the dialog box).

    It's not very common in MicroStation (I do not recall any such situation, but  maybe it exists). But probably there is a reason to do it in opposite order.

    Can I write a function (possibly by inheriting from the DgnElementSetTool class)

    Yes, DgnElementSetTool is extremely flexible (which leads to complex class API), and nearly any workflow can be implemented in inherited class, just by overwriting (once or depending on the workflow state) the class methods.

    and not return a result until the user has either accepted an element or cancelled?

    There is nothing where to return from. It's a misunderstanding how event-driven state machine in MicroStation works. When a tool (command) is active, it's active until another tool is started. When the tool is active, it receives events and can react on them.

    I recommend to study DgnElementSetTool class documentation (also description of parent classes can help). To study examples delivered with MicroStation can help too.

    Regards,

      Jan

  • There is nothing where to return from. It's a misunderstanding how event-driven state machine in MicroStation works. When a tool (command) is active, it's active until another tool is started. When the tool is active, it receives events and can react on them.

    There is no misunderstanding. I have written many MDL commands in v8i. I understand the concept, but I don't know how to implement the workflow I described in CONNECT so I was hoping that someone on the forum could point me in the right direction.

  • Hi Mark,

    but I don't know how to implement the workflow I described in CONNECT

    Maybe I miss something, but I do not see anything special in the workflow you described, so I am not sure where the problem is.

    1. Dialog is opened (of course has to be nonmodal)
    2. It starts element location tool (DgnElementSetTool)
    3. The tool knows what is happening, e.g. when a user select or reject element or another tool is started, so it is able to report this events back to dialog code
    4. When the element is selected, the tool probably can remain active, but can report back to the dialog it should do what is necessary. It's always a matter of discussion (software architecture + application architecture) where the business logic should be implemented: whether close to the tool code or independently and e.g. injected through some interface.
    5. When another tool is started, I guess the dialog should react somehow
    so I was hoping that someone on the forum could point me in the right direction.

    SDK examples contain quite a lot of examples where DgnElementSetTool class is used for element(s) location.

    Regards,

      Jan

  • I don't know how to implement the workflow I described in CONNECT

    Adopt Jan's suggestion to use a pick/locate class that inherits from DgnElementSetTool.

    Here's the difference between procedural programming and object-based programming — your pick class can have member variables.  In this example, let your pick class have a member variable that is a pointer to a dialog box.

    In your dialog, you have a command button that starts the pick operation.  It creates an instance of your pick class.  Assign the dialog pointer to the class member variable.

    Now your pick class can update the dialog at any time via its member variable.

    struct MarkSmitPicker : DgnElementSetTool
    {
       MSDialogP parent_;
       
       MarkSmitPicker (MSDialogP parent) : DgnElementSetTool (), parent_ = parent {}
       
       //void  Parent (MSDialogP parent)  { parent_ = parent; }
       ... other methods
    };

    Usage...

    static public MarkSmitPicker::InstallNewInstance (MSDialogP yourDialog)
        MarkSmitPicker* tool = new MarkSmitPicker (yourDialog);
        tool->InstallTool ();
    

     
    Regards, Jon Summers
    LA Solutions

  • Assign the dialog pointer to the class member variable.

    It's one from possible solutions, but in my opinion it's still too "C style and procedure approach based".

    I would prefer more to implement "a communication object", to create its instance in dialog and to inject it through InstallNewInstance static method (which is often used in examples) and protected class constructor into the instance. In my opinion it's more OOP way how to establish a communication.

    Regards,

      Jan

  • Jan and Jon, thank you for your suggestions. I had a look a the examples and the DgnElementSetTool documentation, which led me to conclude that my original idea cannot be realised the way I had in mind. The alternative is indeed to create an event for the dialog box to respond to a result from the tool whenever this becomes available.

Reply Children
No Data