Nested Dialogs ( first attempt )

Started by Kerry, September 29, 2009, 10:38:18 PM

Previous topic - Next topic

Kerry

I'm attempting to create a routine with the following functionality :
Main Dialog displays a Child Dialog
.. Main is closed so only the Child Dialog is displayed.

Child Dialog 'hides to allow interaction with AutoCAD.
Child Dialog redisplays when interaction is completed.

///---

This works fine for the first 'hide' of the Child.
AutoCAD freezes on the second 'hide'.

The attached piccy is the freeze point ( running a debug animation )

I'm hoping the problem is something simple I'm not doing, or doing incorrectly.

Attached is the LSP and ODCL code.

I'd appreciate a second or third set of eyes ...

T12 is the Command for the nested attempt.
T12Single for the single dialog.

Regards
Kerry

Code (autolisp) Select


;|
Test routine for hiding modal form.

|;
(vl-load-com)
(command "OPENDCL")

;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;|
Main Dialog displays a Child Dialog
.. Main is closed so only a single dialog is displayed.

Child Dialog 'hides to allow interaction with AutoCAD.
Child Dialog redisplays when interaction is completed.

|;

(defun c:t12 (/
              mainflag
              bflag
              ;;
              c:t12_main_selectstuff_onclicked
              c:t12_main_opennew_onclicked
              c:t12_child_selectstuff_onclicked
             )
  ;;---------------------------------------------
  (defun c:t12_main_selectstuff_onclicked (/)
    (setq mainflag t)
    (dcl_form_close t12_main)
    (_dostuff)
  )
  ;;---------------------------------------------
  (defun c:t12_main_opennew_onclicked (/ positionlist main-x main-y)
    (if (dcl_form_isactive t12_main)
      (progn (setq positionlist (dcl_control_getpos t12_main)
                   main-x       (car positionlist)
                   main-y       (cadr positionlist)
             )
             (dcl_form_close t12_main)
      )
    )
    (setq bflag t)
    (while bflag
      (setq bflag nil)
      (dcl_form_show t12_child main-x main-y)
      ;;
    )
  )
  ;;---------------------------------------------
  (defun c:t12_child_selectstuff_onclicked (/)
    (setq bflag t)
    (dcl_form_close t12_child)
    (_dostuff)
  )
  ;;---------------------------------------------
  ;;--------------------------------------------- 
  (or (dcl_project_load "T12" t) (exit))
  (setq mainflag t)
  (while mainflag
    (setq mainflag nil)
    (dcl_form_show t12_main)
    ;;
  )
  (princ)
)
;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;; Library Code common
;;
(defun _dostuff (/ pt blip)
  (setq blip (getvar "BLIPMODE"))
  (setvar "BLIPMODE" 1)
  ;;
  (while (setq pt (getpoint "\n Select a Point"))
    (prompt (strcat "\n " (vl-prin1-to-string pt)))
  )
  ;;
  (setvar "BLIPMODE" blip)
  (redraw)
)
;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;|
Single dialog which 'hides' to allow selection.
Single dialog redisplays when interaction is completed.
|;

(defun c:t12single (/
                    bflag
                    ;;
                    c:t12_child_selectstuff_onclicked
                   )
  (defun c:t12_child_selectstuff_onclicked (/)
    (setq bflag t)
    (dcl_form_close t12_child)
    (_dostuff)
  )
  ;;--------------------------------------------- 
  ;;---------------------------------------------
  (or (dcl_project_load "T12" t) (exit))
  (setq bflag t)
  (while bflag
    (setq bflag nil)
    (dcl_form_show t12_child)
    ;;
  )
  ;;--------------------------------------------- 
  (princ)
)
;;;---------------------------------------------------------------------------
;;;
(prompt "\n T12Single, T12 to run.")
(princ)


Perfection is not optional.
My other home is TheSwamp

Fred Tomke

Hi, Kerry, I'm glad that I can help you  ;)

The answer is easy understandable: Don't leave the car before stopping it! That could harm your health!  ;)

By calling getpoint from an event which was released by a form which is still active (although you've called dcl_form_close in the same event) you force AutoCAD to take control although you haven't give the control back to AutoCAD yet. Everything's clear?

Ok, then this way. Form1 > Pick button for subform > calls event 1 > in this event the form is closed and in the same event function the next form will be shown, even in a while loop in you example > pick point selection button in the subform > calls event 2 > close the form. Now: there are still 2 events in the batch which haven't finished yet.

The solution is to give AutoCAD control far outside the events. For modal forms it means, you must leave the line dcl_form_show at first to give AutoCAD the chance to take control again and then you can AutoCAD ask for input points and objects.

I've moved your code lines around a bit. Here's the solution:

Code (autolisp) Select

(vl-load-com)
(command "OPENDCL")

;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;|
Main Dialog displays a Child Dialog
.. Main is closed so only a single dialog is displayed.

Child Dialog 'hides to allow interaction with AutoCAD.
Child Dialog redisplays when interaction is completed.

|;

(defun c:t12 (/ lstFormPos intForm
             c:t12_main_selectstuff_onclicked
             c:t12_main_opennew_onclicked
            )
 (defun c:t12_main_selectstuff_onclicked (/)
   (dcl_form_close t12_main 3)
 ); c:t12_main_selectstuff_onclicked

 (defun c:t12_main_opennew_onclicked (/)
   (setq lstFormPos (dcl_control_getpos t12_main))
   (dcl_form_close t12_main 4)
 ); c:t12_main_opennew_onclicked

 (load_project)
 (while (/= (setq intForm
                   (if lstFormPos
                     (dcl_form_show t12_main (car lstFormPos) (cadr lstFormPos))
                     (dcl_form_show t12_main)
                   ); if
                  ) 2) ;; 2 is for escaping the form!
   (cond
     ((= intForm 3) (_dostuff))
     ((= intForm 4) (call_child))
   ); cond
 ); while
 (princ)
); t12

;; Call subform alone

(defun c:t12single ()
 (call_child)
 (princ)
); c:t12single


;; ===================
;; Library Code common
;; ===================

(defun load_project ()
 (or (member "T12" (dcl_getprojects)) (dcl_project_load "T12") (exit))
); load_project

(defun _dostuff (/ pt blip)
 (setq blip (getvar "BLIPMODE"))
 (setvar "BLIPMODE" 1)

 (while (setq pt (getpoint "\n Select a Point"))
   (prompt (strcat "\n " (vl-prin1-to-string pt)))
 ); while

 (setvar "BLIPMODE" blip)
 (redraw)
); _dostuff

(defun call_child (/ intForm c:t12_child_selectstuff_onclicked)

 (defun c:t12_child_selectstuff_onclicked (/)
   (dcl_form_close t12_child 3)
 ); c:t12_child_selectstuff_onclicked

 (load_project)
 (while (/= (setq intForm (dcl_form_show t12_child)) 2)
   (cond
     ((= intForm 3) (_dostuff))
   ); cond
 ); while
 
); call_child

(prompt "\n T12Single, T12 to run.")
(princ)



Fred
Fred Tomke
Dipl.-Ing. (FH) Landespflege

[ landscaper - landscape developer - digital landscape and urban design]

Kerry

#2
Thanks Fred !!

I'm running out the door to catch my train .. I'll have a look tomorrow.


Your blood is worth bottling :)

Regards
Kerry

ps
second thoughts
Ill print it and read on the train :)
Perfection is not optional.
My other home is TheSwamp

BazzaCAD

Quote from: Kerry Brown on September 29, 2009, 11:43:15 PM
Your blood is worth bottling :)

What... ??? He gives you a great solution & you want to kill him (that's not very nice) :)
a.k.a.
Barry Ralphs
barryDOTralphsATgmailDOTcom

Kerry


Yes, it is a great solution.
and no, I wouldn't harm him :)
Perfection is not optional.
My other home is TheSwamp

Kerry


Thanks Fred, The concept works great.

I've set some enumerators for the DialogStatus
passed to  dcl_Form_Show
and returned from dcl_Form_Close

This is my revised code :-
Regards,
Kerry

Code (autolisp) Select

(vl-load-com)
(command "OPENDCL")

;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;|
Main Dialog displays a Child Dialog
.. Main is closed so only a single dialog is displayed.

Child Dialog 'hides to allow interaction with AutoCAD.
Child Dialog redisplays when interaction is completed.

|;

(defun c:T12 (/
              MainFormPosition
              DialogStatus
              c:T12_Main_SelectStuff_onclicked
              c:T12_Main_OpenNew_onclicked
             )
  ;;---------------------------------------------
  ;; establish GLOBAL VARIABLES for DialogStatus
  (_set_DialogStatusEnumerators)
  ;;---------------------------------------------
  (defun c:T12_Main_SelectStuff_onclicked (/)
    (dcl_form_close T12_Main e_SelectStuff)
  )
  ;;---------------------------------------------
  (defun c:T12_Main_OpenNew_onclicked (/)
    (setq MainFormPosition (dcl_control_getpos T12_Main))
    (dcl_form_close T12_Main e_Display_Child)
  )
  ;;---------------------------------------------
  (_Load_Project "T12")
  ;;---------------------------------------------
  (while (/= (setq DialogStatus (if MainFormPosition
                                  (dcl_form_show T12_Main
                                                 (car MainFormPosition)
                                                 (cadr MainFormPosition)
                                  )
                                  (dcl_form_show T12_Main)
                                )
             )
             e_Form_Cancelled
         )
    (cond ((= DialogStatus e_SelectStuff) (_doStuff))
          ((= DialogStatus e_Display_Child) (_Call_Child))
    )
  )
  (princ)
)
;;;---------------------------------------------------------------------------
;;;
;; Call subform alone

(defun c:T12Single (/)
  ;;---------------------------------------------
  ;; establish GLOBAL VARIABLES for DialogStatus
  (_set_DialogStatusEnumerators)
  ;;---------------------------------------------
  (_Call_Child)
  (princ)
)
;;;---------------------------------------------------------------------------
;;;
;;;---------------------------------------------------------------------------
;;;
;; ===================
;; Library Code common
;; ===================

(defun _Load_Project (ProjectName)
  (or (member ProjectName (dcl_getprojects))
      (dcl_project_load ProjectName)
      (exit)
  )
)
;;;---------------------------------------------------------------------------
;;;
;; establish GLOBAL VARIABLES for DialogStatus
;|
  The Forms are Modal, so the dcl_Form_Show does not return until the dialog is closed,
  and it returns a long value that indicates the dialog status.
  If a dialog is cancelled (e.g. by pressing [Esc]), the return value is 2;
  if it is closed by pressing [Enter], the return value is 1.
 
  Other values may be returned by calling dcl_Form_Close from an event handler
  and specifying a custom dialog status.
  If the optional DialogStatus argument for dcl_Form_Close is provided when closing a modal dialog,
  it will become the return value for the call to dclForm_Show that displayed the modal dialog.
 
  |;
(defun _set_DialogStatusEnumerators ()
  (setq e_EnterPressed 1
        e_Form_Cancelled 2
        e_SelectStuff 123
        e_Display_Child 124
  )
)

;;;---------------------------------------------------------------------------
;;;
(defun _doStuff (/ pt blip)
  (setq blip (getvar "BLIPMODE"))
  (setvar "BLIPMODE" 1)
  (while (setq pt (getpoint "\n Select a Point"))
    (prompt (strcat "\n " (vl-prin1-to-string pt)))
  )
  (setvar "BLIPMODE" blip)
  (redraw)
)
;;;---------------------------------------------------------------------------
;;;
(defun _Call_Child (/ DialogStatus c:t12_child_SelectStuff_onclicked)
  (defun c:t12_child_SelectStuff_onclicked (/)
    (dcl_form_close t12_child e_SelectStuff)
  )
  ;;---------------------------------------------
  (_Load_Project "T12")
  (while (/= (setq DialogStatus (dcl_form_show T12_Child))
             e_Form_Cancelled
         )
    (cond ((= DialogStatus e_SelectStuff) (_doStuff)))
  )
)
;;;---------------------------------------------------------------------------
;;;

(prompt "\n T12Single, T12 to run.")
(princ)
;;;---------------------------------------------------------------------------
;;;
Perfection is not optional.
My other home is TheSwamp

BazzaCAD

This is some pretty cool code guys...
a.k.a.
Barry Ralphs
barryDOTralphsATgmailDOTcom

Kerry


Fred,
           { or in fact anyone }

Have you sucesfully used
A main Form
A Child Form { or several Child Forms }

Where :
The Main stays Displayed when the Child is Active.

From Main :
    For Interaction with AutoCAD :- Closes Main , and redisplays on return.

From Child :
    For Interaction with AutoCAD :- Closes Main , Closes Child ... and redisplays both on return.


Regards
Kerry
Perfection is not optional.
My other home is TheSwamp

Fred Tomke

Hi, Kerry, it depends on what can be done in the child form. As long the child form never needs interaction from AutoCAD prompt (points, objects ...) I'll keep the main form active behind the child form. In all the cases where (1.) the user may pick points or objects from the drawing or (2.) AutoCAD dialogs are going to be shown which do need full control to AutoCAD (like text style manager from AutoCAD or classic layer properties manager), I close the main form before showing the child form. I often thought about such a case: closing both and reopen both. But it ever seemed to me too complicated to solve. Especially, I see no way to open the child (modal) form in the same context the main (modal) form is being shown. I mean if you send the line (dcl_form_show mainform) you cannot add another line for (dcl_form_show childform) afterwards anymore. And I don't believe (I mean: haven't try it yet) that I can call (dcl_form_show childform) from the OnInitialize-event of the main form (it would work if the child form is a modeless form).

I hope that I explained it understandable enough with my poor English.

Fred
Fred Tomke
Dipl.-Ing. (FH) Landespflege

[ landscaper - landscape developer - digital landscape and urban design]

Kerry

#9
Fred,
Your English is perfectly understandable, thanks.


I do need the Main visible when the Child is active .. so the user can see some of the Main settings.

The Child will call a draw process in AutoCAD.

Then I'd like Both the Main and a Child to redisplay.


As you say, it is a complicated case.

I had thought to use Tabs for the Children (about 9) but the Child size and layout requirements are too different.
... I may need to revisit this option.

added:
or perhaps consider using nodeless forms for this application.

Regards
Kerry



Perfection is not optional.
My other home is TheSwamp

Fred Tomke

Hi Kerry,

yes both of your thoughts (tabs and modeless) could be usable alternativs. I do use them, too.

A) Tabs: We have one form with many global settings for the drawing. In a few settings the form has to be closed for picking points. Using tabs is very comfortable (as well as for user and developer  ;) ) in this case.

B) Modeless: Meanwhile I created some wizards where the user can either pick points in the drawing to change settings for distance or he can change the value in a form. Because it's not very comfortable for the user to press a button at first to close the form to pick at the screen for each setting, I decided to keep a modeless form open so the user can decide whether to select on screen or change in the form.

I think that the way to solve this depends on the amount of hiding and reshowing the form. The more the form has to be closed for objects, points or settings, the more a modeless form may be better.

Fred
Fred Tomke
Dipl.-Ing. (FH) Landespflege

[ landscaper - landscape developer - digital landscape and urban design]

owenwengerd

As a general rule, if you're faced with this kind of dilemma, your UI is too complicated and needs to be designed differently. Going modeless might be one simple solution.

You could probably solve the "reshow both dialogs" problem that Fred describes by utilizing the (dcl_DelayInvoke) function to "delay-invoke" a function that shows the child, then immediately call (dcl_Form_Show) to show the parent. However, the very fact that you need to do this leads me to suspect that the best solution is a redesign.

BazzaCAD

a.k.a.
Barry Ralphs
barryDOTralphsATgmailDOTcom

velasquez

#13
Quote from: Fred Tomke on October 02, 2009, 04:39:18 PM
Hi Kerry,

yes both of your thoughts (tabs and modeless) could be usable alternativs. I do use them, too.

A) Tabs: We have one form with many global settings for the drawing. In a few settings the form has to be closed for picking points. Using tabs is very comfortable (as well as for user and developer  ;) ) in this case.

B) Modeless: Meanwhile I created some wizards where the user can either pick points in the drawing to change settings for distance or he can change the value in a form. Because it's not very comfortable for the user to press a button at first to close the form to pick at the screen for each setting, I decided to keep a modeless form open so the user can decide whether to select on screen or change in the form.

I think that the way to solve this depends on the amount of hiding and reshowing the form. The more the form has to be closed for objects, points or settings, the more a modeless form may be better.

Fred

Hello Fred, 
You worked with grread or grdraw with this function?

Greetings Velasquez

Fred Tomke

Hi, velasquez, yes, with grread and grdraw.
Fred
Fred Tomke
Dipl.-Ing. (FH) Landespflege

[ landscaper - landscape developer - digital landscape and urban design]