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?
Hi Mark,
MarkSmit said:I have thought about :
Wrong, it will not work.
MarkSmit said:My question is: what is the best way to solve this?
When you want to implement any tool, that will require to locate an element, the standard way is to inherit DgnElementSetTool class and to implement own modification command. The class encapsulates complete logic and covers the most of integration task with the rest of MicroStation (initiate new transaction, start dynamics when required, update GUI properly...).
MarkSmit said:I have have an application that creates its own dialog box
It's not clear what is the exact tool workflow, but it's fine to start MicroStation tool (anything inherited from DgnTool) and to open e.g. own dialog. When possible, it's recommended to use Tool Settings dialog only to follow MicroStation standards and UX best practices.
With regards,
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
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.
MarkSmit said: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.
MarkSmit said: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.
MarkSmit said: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 Šlegr said: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.
MarkSmit said: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.
MarkSmit said: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.
MarkSmit said: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.
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
Jon Summers said: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.
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.