I have a dialog box in which I can select a module path. String s becomes that module path and then that module is read. That much works. But when I go to export that module, the script pukes. I get a "Non local variable access (diag)" error, plus several errors occur within the standard scripts called by "commas.dxl". I'm not sure what the problem is since I made sure to use unique variables with the dialogs. Why doesn't this work? Is the checkbox dialog box staying open, and the script getting confused between it and the export dialog?
DB projBox = null
DBE projectCheck = null
string projectList[] = {"/folder/module1","/folder/module2","/folder/module3"}
void doCancel (DB db)
{
hide db
destroy db
projBox = null
}
void doGo(DB bx)
{
int i
for(i = 1; i < sizeof(projectList); i++)
{
if (getCheck(projectCheck,i))
{
string s = getColumnValue(projectCheck, i,0)
}
}
hide projBox
read(s, false)
DB diag = null
void show(DB x)
{
realize x
diag = x
}
#include <standard/export/commas.dxl>
expSprExportCB(diag)
hide diag
}
projBox = create "Projects"
projectCheck = listView(projBox, listViewOptionCheckboxes|listViewOptionMultiselect, 200, 10, projectList)
close(projBox, false, doCancel)
apply(projBox, "Cancel", doCancel)
apply(projBox, "Go", doGo)
realize projBox
insertColumn(projectCheck,0,"Selection",150,iconUser)
show projBox
moheganburnerIII - Mon Oct 10 14:54:34 EDT 2011 |
|
Re: Multiple Dialog Box Confusion llandale - Mon Oct 10 15:28:31 EDT 2011
DXL is rather restricted. You can only use a variable when its defined in the local function or when its defined in the global context. This fails:
int i
void t()
{ int i
void t1() // function embedded in function t()
{ i = 5
}
}
Line 5: i = 5 knows it wants to access variable "i" defined at line 3, but since that variable is not defined in the current function t1 nor in the global context, as is "i" in line 1.
In this case your include file commas.dxl has some variables in its global context, but that context changes when you #include it inside your function doGo(); those variables are not defined in the function.
You could re-arrange this using "block" instead of "show" and move the bulk of your doGo() in the global context after "block". This will put "#include <standard/export/commas.dxl>
" in the global context.
|
|
Re: Multiple Dialog Box Confusion moheganburnerIII - Mon Oct 10 16:45:18 EDT 2011
I kinda figured that, so I've been moving parts of the dogo around all day with no luck. Changing "show" to "block" is something I've seen recommended to others before, but what part of the doGo can I move out? how can any part of it be moved out of the call???
|
|
Re: Multiple Dialog Box Confusion llandale - Mon Oct 10 18:30:11 EDT 2011 llandale - Mon Oct 10 15:28:31 EDT 2011
DXL is rather restricted. You can only use a variable when its defined in the local function or when its defined in the global context. This fails:
int i
void t()
{ int i
void t1() // function embedded in function t()
{ i = 5
}
}
Line 5: i = 5 knows it wants to access variable "i" defined at line 3, but since that variable is not defined in the current function t1 nor in the global context, as is "i" in line 1.
In this case your include file commas.dxl has some variables in its global context, but that context changes when you #include it inside your function doGo(); those variables are not defined in the function.
You could re-arrange this using "block" instead of "show" and move the bulk of your doGo() in the global context after "block". This will put "#include <standard/export/commas.dxl>
" in the global context.
Your cancel callback should be hide/destroy/release(db)/halt. Your DoGo callback should be just hide/release. The code after the "block" command will execute only when DoGo was called. It does what the current DoGo does, with destroy(projBox) instead of hide it (again).
While I'm looking at it, I think you really need to get the Handle of the open module, then set that module current:
.. Module mod = read(s, false, true)
.. current = mod
commas.inc expects a current module, yes?
Your multiSelect option looks questionable as your "for i" loop will result in "s" having only the last value.
Its beyond me, but I'm suspecting that using these native include files may best be done in eval_ executed code. Build the big string that has your clever "show" override along with opening the module and setting it current, and isuing the #include. Once we figure out how to do that cleanly and no doubt in some clever library function, we can use those includes from within the body of our more massive scripts.
|
|
Re: Multiple Dialog Box Confusion moheganburnerIII - Mon Oct 10 21:31:08 EDT 2011
Funny...I always try to whittle my code down to focus on what my real problem is, but everytime I do that, I wind up exposing problems I don't really have. The full code does get a handle on the current module, and the "string s" line is instead a skiplist put. All selections are then looped through, massaged (via even more undisclosed code) and exported via #include. My bad, I should really stop abridging my code posts.
I think I'm following you. I guess the goal is to get the:
hide projBox
read(s, false)
DB diag = null
void show(DB x)
{
realize x
diag = x
}
#include <standard/export/commas.dxl>
expSprExportCB(diag)
hide diag
portion out of doGo...which is what I originally tried to do (before I posted here), but kept getting other errors. I also noticed that when I was experimenting with "block" earlier, I was getting my print outputs, but then when the code was done running, I couldn't touch either the dxl interactive window or the DOORS main application window. There wasn't an hourglass, but it seemed like something was still running and wouldn't let me do anything else. I'll mess around with it tomorrow. Thanks for the added wisdom!
|
|
Re: Multiple Dialog Box Confusion moheganburnerIII - Tue Oct 11 09:18:17 EDT 2011
All I had to do was this. Thanks for the help!
DB projBox = null
DBE projectCheck = null
string projectList[] = {"/folder/module1","/folder/module2","/folder/module3"}
void doCancel (DB db)
{
hide db
destroy db
projBox = null
}
void doGo(DB bx)
{
int i
for(i = 1; i < sizeof(projectList); i++)
{
if (getCheck(projectCheck,i))
{
string s = getColumnValue(projectCheck, i,0)
}
}
hide projBox
release projBox
}
projBox = create "Projects"
projectCheck = listView(projBox, listViewOptionCheckboxes|listViewOptionMultiselect, 200, 10, projectList)
close(projBox, false, doCancel)
apply(projBox, "Cancel", doCancel)
apply(projBox, "Go", doGo)
realize projBox
insertColumn(projectCheck,0,"Selection",150,iconUser)
block projBox
read(s, false)
DB diag = null
void show(DB x)
{
realize x
diag = x
}
#include <standard/export/commas.dxl>
expSprExportCB(diag)
hide diag
destroy projBox
|
|
Re: Multiple Dialog Box Confusion moheganburnerIII - Tue Oct 11 09:53:40 EDT 2011
Spoke too soon. My cancel callback is cancelling, but it's freezing the DOORS windows and forcing me to close out via task manager. My code is like I just posted, except my cancel callback now looks like:
void doCancel (DB db)
{
hide db
destroy db
release db
halt
hide projBox
release projBox
destroy projBox
}
It seems to me that I have to destroy the projBox within the cancel, but I could be wrong. Are my instructions in the wrong order???
|
|
Re: Multiple Dialog Box Confusion llandale - Tue Oct 11 10:56:28 EDT 2011 moheganburnerIII - Tue Oct 11 09:53:40 EDT 2011
Spoke too soon. My cancel callback is cancelling, but it's freezing the DOORS windows and forcing me to close out via task manager. My code is like I just posted, except my cancel callback now looks like:
void doCancel (DB db)
{
hide db
destroy db
release db
halt
hide projBox
release projBox
destroy projBox
}
It seems to me that I have to destroy the projBox within the cancel, but I could be wrong. Are my instructions in the wrong order???
Not sure how you are getting information "s" from your function down into your main code so you can read it. That;s why I suggested reading the dialog after the block, then destroying it.
As for your cancel below, variable "db" should be the same as your projBox variable, but when you set "db" to null you do NOT set projBox to null. Just about all my DB and DBE callbacks, I ignore the input DB in_dbXX or DBE in_dbeXX; since that function is written for a particular DB or DBE anyway. Once in a while I'll write a generic callback, which looks at the input to see what its dealing with so it knows what its supposed to do.
I wonder about the usefulness of a "halt" in your cancel callback; in this case it will prevent the next 3 lines from executing, and I wonder if that will stop the code after the "block" from executing.
|
|
Re: Multiple Dialog Box Confusion Mathias Mamsch - Tue Oct 11 19:00:18 EDT 2011 moheganburnerIII - Tue Oct 11 09:53:40 EDT 2011
Spoke too soon. My cancel callback is cancelling, but it's freezing the DOORS windows and forcing me to close out via task manager. My code is like I just posted, except my cancel callback now looks like:
void doCancel (DB db)
{
hide db
destroy db
release db
halt
hide projBox
release projBox
destroy projBox
}
It seems to me that I have to destroy the projBox within the cancel, but I could be wrong. Are my instructions in the wrong order???
Could people please stop to call destroy in a callback?? It makes the programs unstable and leaks memory (and the DXL help says you shall not do it, although its examples do it itself!). The correct approach for blocking windows is:
void myCallback(DB diag) {
hide diag // only do hide in a callback.
}
DB diag = create "Hallo"
ok(diag, "OK", myCallback)
// always do block and release together.
// This way your GUIs will not 'block' forever if in some callback you forgot to release
block(diag); release(diag);
// read the dialog elements here! If you want....
destroy(diag)
For your export problem you might be better served with an eval_ approach as described here:
https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14691974#14691974
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
|
|
Re: Multiple Dialog Box Confusion llandale - Wed Oct 12 14:52:19 EDT 2011 Mathias Mamsch - Tue Oct 11 19:00:18 EDT 2011
Could people please stop to call destroy in a callback?? It makes the programs unstable and leaks memory (and the DXL help says you shall not do it, although its examples do it itself!). The correct approach for blocking windows is:
void myCallback(DB diag) {
hide diag // only do hide in a callback.
}
DB diag = create "Hallo"
ok(diag, "OK", myCallback)
// always do block and release together.
// This way your GUIs will not 'block' forever if in some callback you forgot to release
block(diag); release(diag);
// read the dialog elements here! If you want....
destroy(diag)
For your export problem you might be better served with an eval_ approach as described here:
https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14691974#14691974
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
The 'release' goes in the close callback, the 'hide' and 'destroy' go after the 'block'. And I wonder if you really need 'hide' since the 'release' seems to also 'hide', and anyway surely 'destroy' also hides it.
|
|
Re: Multiple Dialog Box Confusion Mathias Mamsch - Thu Oct 13 08:59:02 EDT 2011 llandale - Wed Oct 12 14:52:19 EDT 2011
The 'release' goes in the close callback, the 'hide' and 'destroy' go after the 'block'. And I wonder if you really need 'hide' since the 'release' seems to also 'hide', and anyway surely 'destroy' also hides it.
In my opinion this is not the best way to handle it (a good way though).
Block/Release:
-
When you block stuff you need to release it. Therefore release should go with block and not in the callback.
-
Then when you want to 'show' your dialog instead of blocking it, just remove the block; release and replace by show. No other change needed.
-
When you add a callback that wants to end the dialog, usually I forget the release first, my program freezes, I need to restart DOORS. When you have 7 callbacks that want to close the dialog for whatever reason you will have 7 releases. Cannot happen when you bundle release with block.
Destroy:
-
Don't do destroy in a callback. It is unstable, leaks memory and crashes from time to time. And since a 'show'n dialog will not execute code that comes after show this means: Don't destroy a 'show'n dialog. Therefore put the destroy after block, and only when you use block. Don't use it at all when you use show.
Hide: Hide is in my opinion the best way to end a dialog. Sure once can use release, but this will have no effect when the dialog is shown. Hide works regardless if you use show or block. You are right when you say that doing 'hide' and 'destroy' is not necessary, because hide is implicly contained in destroy. But I like the idea of having only one way to end a dialog. Since release also seems to hide there is no reason to use release in callbacks instead of hide.
Therefore I would suggest the following practice as 'best'-practice, because they are simple:
-
use 'hide dbVar' to end a dialog in callbacks
-
use 'block dbVar; release dbVar; destroy dbVar' for modal dialogs (i.e. the user cannot work in other windows)
-
use 'show dbVar' to show a non modal dialog
Opinions?
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
|
|
Re: Multiple Dialog Box Confusion llandale - Thu Oct 13 15:44:58 EDT 2011 Mathias Mamsch - Thu Oct 13 08:59:02 EDT 2011
In my opinion this is not the best way to handle it (a good way though).
Block/Release:
-
When you block stuff you need to release it. Therefore release should go with block and not in the callback.
-
Then when you want to 'show' your dialog instead of blocking it, just remove the block; release and replace by show. No other change needed.
-
When you add a callback that wants to end the dialog, usually I forget the release first, my program freezes, I need to restart DOORS. When you have 7 callbacks that want to close the dialog for whatever reason you will have 7 releases. Cannot happen when you bundle release with block.
Destroy:
-
Don't do destroy in a callback. It is unstable, leaks memory and crashes from time to time. And since a 'show'n dialog will not execute code that comes after show this means: Don't destroy a 'show'n dialog. Therefore put the destroy after block, and only when you use block. Don't use it at all when you use show.
Hide: Hide is in my opinion the best way to end a dialog. Sure once can use release, but this will have no effect when the dialog is shown. Hide works regardless if you use show or block. You are right when you say that doing 'hide' and 'destroy' is not necessary, because hide is implicly contained in destroy. But I like the idea of having only one way to end a dialog. Since release also seems to hide there is no reason to use release in callbacks instead of hide.
Therefore I would suggest the following practice as 'best'-practice, because they are simple:
-
use 'hide dbVar' to end a dialog in callbacks
-
use 'block dbVar; release dbVar; destroy dbVar' for modal dialogs (i.e. the user cannot work in other windows)
-
use 'show dbVar' to show a non modal dialog
Opinions?
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
I think you are confusing some features of 'show' with 'block'. Talking only about block ed dialogs:
-
Blocking locks the DOORS interface, except for dialogs and modules opened inside the dialog's callbacks.
-
The ONLY way that code after the 'block' command will execute is when you have issued a release inside some callback function. Code after 'block' begins executing after the callback ends naturally. This is not optional, you MUST 'release' a 'block'ed dialog in a callback. A 'release' after the block cannot do anything useful since in order for it to execute, it must already be released.
-
If you hide in a callback and do not also 'release', the dialog disappears and DOORS is locked up since, well, the DOORS interface is locked when you block; and that dialog was never 'released'. I emphasize that the code after 'block' does NOT execute in this case. See 1st code below. Perhaps there is a way to recover, but I think only if some other sub-dialog is running that is coded to handle a hidden main block dialog.
-
I agree that destroy in a blocked callback is bad because DOORS still needs the dialog box in order to finish executing the 'release', which occurs after the callback ends naturally and is by definition AFTER you destroy it. You are rolling the dice as to whether DOORS corrupts that de-allocated space; or has other issues that you understand far better than me.
-
I disagree, the only real reason to hide instead of 'destroy' is when you figure to re-use that complicated dialog later, and its a sub-dialog of some other relatively permanant dialog. In this case, the create-sub-dialog code would check to see if that sub-dialog has already been created, and if so skips the create and proceeds straight to the block. That particular scenario (which I've explained clear-as-a-bell!) is rare and not particularly useful anyway, meaning the vast majority of time you will 'destroy' and not bother to 'hide'.
Run the following code. If you 'cancel' then you get the final infobox (the native cancel issues a 'release'), if you 'Lock DOORS Interface' and then confirm, you issue a naked 'hide' and lock the doors interface.
DB db
void clbkHide(DB dbXX)
{ if (confirm("Are you SURE you want to 'hide' and permanantly lock up DOORS," //
"\nforcing you to use Task Manager to kill it???")) //
then hide(db)
}
db = create("Blocked Dialog")
apply(db, "Lock DOORS Interface", clbkHide)
block(db)
infoBox("After 'block(db)'")
It seems to me then that you should write a simple 'close' callback and invoke that, then have all the callbacks that want to close the blocked dialog call the close callback. The simple close callback would delete whatever data structures you've created for the dialog (if any), issue 'release', and end. The code after the block is the 'destroy', although you could 'hide' and leave a little memory tied up and lost for the rest of the DOORS session. Basically looks like this:
Skip skpOK = null,
skpCheck = null
DB dbDialog
void clbkClose(DB dbXX)
{ if (!null skpOK) delete(skpOK)
if (!null skpCheck) delete(skpCheck)
release(dbDialog)
}
void clbkOK(DB dbXX)
{ if (!null skpOK) delete(skpOK)
skpOK = create()
// do real work here
clbkClose(dbXX)
}
void clbkCheck(DB dbXX)
{ if (!null skpCheck) delete(skpCheck)
skpCheck = create()
// do real work here
// keep dialog open
}
dbDialog = create("Blocked Dialog")
apply(dbDialog, "Check", clbkCheck)
apply(dbDialog, "OK", clbkOK)
block(dbDialog)
infoBox("After block")
destroy(dbDialog)
If you don't want a close callback, then all the callbacks that want to close the dialog would issue a 'release', but that's the same thing as calling the close instead.
As for show dialog. I think you should likewise have a clean-up 'close' callback that cleans up data structures and issues the 'destroy', unless for some reason you want to preserve the dialog for future 'show' without having to re-build it; in which case you would 'hide'.
|
|
Re: Multiple Dialog Box Confusion Mathias Mamsch - Sat Oct 15 06:25:01 EDT 2011 llandale - Thu Oct 13 15:44:58 EDT 2011
I think you are confusing some features of 'show' with 'block'. Talking only about block ed dialogs:
-
Blocking locks the DOORS interface, except for dialogs and modules opened inside the dialog's callbacks.
-
The ONLY way that code after the 'block' command will execute is when you have issued a release inside some callback function. Code after 'block' begins executing after the callback ends naturally. This is not optional, you MUST 'release' a 'block'ed dialog in a callback. A 'release' after the block cannot do anything useful since in order for it to execute, it must already be released.
-
If you hide in a callback and do not also 'release', the dialog disappears and DOORS is locked up since, well, the DOORS interface is locked when you block; and that dialog was never 'released'. I emphasize that the code after 'block' does NOT execute in this case. See 1st code below. Perhaps there is a way to recover, but I think only if some other sub-dialog is running that is coded to handle a hidden main block dialog.
-
I agree that destroy in a blocked callback is bad because DOORS still needs the dialog box in order to finish executing the 'release', which occurs after the callback ends naturally and is by definition AFTER you destroy it. You are rolling the dice as to whether DOORS corrupts that de-allocated space; or has other issues that you understand far better than me.
-
I disagree, the only real reason to hide instead of 'destroy' is when you figure to re-use that complicated dialog later, and its a sub-dialog of some other relatively permanant dialog. In this case, the create-sub-dialog code would check to see if that sub-dialog has already been created, and if so skips the create and proceeds straight to the block. That particular scenario (which I've explained clear-as-a-bell!) is rare and not particularly useful anyway, meaning the vast majority of time you will 'destroy' and not bother to 'hide'.
Run the following code. If you 'cancel' then you get the final infobox (the native cancel issues a 'release'), if you 'Lock DOORS Interface' and then confirm, you issue a naked 'hide' and lock the doors interface.
DB db
void clbkHide(DB dbXX)
{ if (confirm("Are you SURE you want to 'hide' and permanantly lock up DOORS," //
"\nforcing you to use Task Manager to kill it???")) //
then hide(db)
}
db = create("Blocked Dialog")
apply(db, "Lock DOORS Interface", clbkHide)
block(db)
infoBox("After 'block(db)'")
It seems to me then that you should write a simple 'close' callback and invoke that, then have all the callbacks that want to close the blocked dialog call the close callback. The simple close callback would delete whatever data structures you've created for the dialog (if any), issue 'release', and end. The code after the block is the 'destroy', although you could 'hide' and leave a little memory tied up and lost for the rest of the DOORS session. Basically looks like this:
Skip skpOK = null,
skpCheck = null
DB dbDialog
void clbkClose(DB dbXX)
{ if (!null skpOK) delete(skpOK)
if (!null skpCheck) delete(skpCheck)
release(dbDialog)
}
void clbkOK(DB dbXX)
{ if (!null skpOK) delete(skpOK)
skpOK = create()
// do real work here
clbkClose(dbXX)
}
void clbkCheck(DB dbXX)
{ if (!null skpCheck) delete(skpCheck)
skpCheck = create()
// do real work here
// keep dialog open
}
dbDialog = create("Blocked Dialog")
apply(dbDialog, "Check", clbkCheck)
apply(dbDialog, "OK", clbkOK)
block(dbDialog)
infoBox("After block")
destroy(dbDialog)
If you don't want a close callback, then all the callbacks that want to close the dialog would issue a 'release', but that's the same thing as calling the close instead.
As for show dialog. I think you should likewise have a clean-up 'close' callback that cleans up data structures and issues the 'destroy', unless for some reason you want to preserve the dialog for future 'show' without having to re-build it; in which case you would 'hide'.
Darn, you are right ... It seems that you can end a blocked dialog with hide only from a callback that was registered by "ok(DB, ...)". Doing it from apply or a normal button callback does indeed freeze DOORS. That exception mislead me.
So what is the foolproof way to handle dialog boxes then? My suggestion would be to always do 'release x; hide x' in a callback to end a dialog. I know that it has redundancy in it, but I am thinking about all those people learning DXL having their dialogs freeze their DOORS client. So I will modify my suggestion for a best practice:
So I correct my suggested best-practices:
-
use 'release dbVar; hide dbVar' to end a dialog in callbacks
-
use 'block dbVar; destroy dbVar' for modal dialogs (i.e. the user cannot work in other windows)
-
use 'show dbVar' to show a non modal dialog
-
in more complex programs, introduce a cleanup method, which will close the dialog (by calling release, hide) and free any allocated ressources.
What do you think? I still think it is nice to have a unique way to handle 'show' and 'block'
Regards, Mathias
DB db
void clbkHideDBE(DBE dbXX) {
DB db = getParent dbXX
release db; hide(db)
}
void clbkHideDB(DB db) {
release db; hide(db)
}
db = create("Blocked Dialog")
ok (db, "OK close" , clbkHideDB)
apply (db, "Apply close" , clbkHideDB)
button(db, "Button Close", clbkHideDBE)
if (confirm "Show it?") {
show db
} else {
block db;
// evaluate dialog contents here ...
destroy db
}
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
|
|
Re: Multiple Dialog Box Confusion Mathias Mamsch - Sat Oct 15 06:52:44 EDT 2011 llandale - Thu Oct 13 15:44:58 EDT 2011
I think you are confusing some features of 'show' with 'block'. Talking only about block ed dialogs:
-
Blocking locks the DOORS interface, except for dialogs and modules opened inside the dialog's callbacks.
-
The ONLY way that code after the 'block' command will execute is when you have issued a release inside some callback function. Code after 'block' begins executing after the callback ends naturally. This is not optional, you MUST 'release' a 'block'ed dialog in a callback. A 'release' after the block cannot do anything useful since in order for it to execute, it must already be released.
-
If you hide in a callback and do not also 'release', the dialog disappears and DOORS is locked up since, well, the DOORS interface is locked when you block; and that dialog was never 'released'. I emphasize that the code after 'block' does NOT execute in this case. See 1st code below. Perhaps there is a way to recover, but I think only if some other sub-dialog is running that is coded to handle a hidden main block dialog.
-
I agree that destroy in a blocked callback is bad because DOORS still needs the dialog box in order to finish executing the 'release', which occurs after the callback ends naturally and is by definition AFTER you destroy it. You are rolling the dice as to whether DOORS corrupts that de-allocated space; or has other issues that you understand far better than me.
-
I disagree, the only real reason to hide instead of 'destroy' is when you figure to re-use that complicated dialog later, and its a sub-dialog of some other relatively permanant dialog. In this case, the create-sub-dialog code would check to see if that sub-dialog has already been created, and if so skips the create and proceeds straight to the block. That particular scenario (which I've explained clear-as-a-bell!) is rare and not particularly useful anyway, meaning the vast majority of time you will 'destroy' and not bother to 'hide'.
Run the following code. If you 'cancel' then you get the final infobox (the native cancel issues a 'release'), if you 'Lock DOORS Interface' and then confirm, you issue a naked 'hide' and lock the doors interface.
DB db
void clbkHide(DB dbXX)
{ if (confirm("Are you SURE you want to 'hide' and permanantly lock up DOORS," //
"\nforcing you to use Task Manager to kill it???")) //
then hide(db)
}
db = create("Blocked Dialog")
apply(db, "Lock DOORS Interface", clbkHide)
block(db)
infoBox("After 'block(db)'")
It seems to me then that you should write a simple 'close' callback and invoke that, then have all the callbacks that want to close the blocked dialog call the close callback. The simple close callback would delete whatever data structures you've created for the dialog (if any), issue 'release', and end. The code after the block is the 'destroy', although you could 'hide' and leave a little memory tied up and lost for the rest of the DOORS session. Basically looks like this:
Skip skpOK = null,
skpCheck = null
DB dbDialog
void clbkClose(DB dbXX)
{ if (!null skpOK) delete(skpOK)
if (!null skpCheck) delete(skpCheck)
release(dbDialog)
}
void clbkOK(DB dbXX)
{ if (!null skpOK) delete(skpOK)
skpOK = create()
// do real work here
clbkClose(dbXX)
}
void clbkCheck(DB dbXX)
{ if (!null skpCheck) delete(skpCheck)
skpCheck = create()
// do real work here
// keep dialog open
}
dbDialog = create("Blocked Dialog")
apply(dbDialog, "Check", clbkCheck)
apply(dbDialog, "OK", clbkOK)
block(dbDialog)
infoBox("After block")
destroy(dbDialog)
If you don't want a close callback, then all the callbacks that want to close the dialog would issue a 'release', but that's the same thing as calling the close instead.
As for show dialog. I think you should likewise have a clean-up 'close' callback that cleans up data structures and issues the 'destroy', unless for some reason you want to preserve the dialog for future 'show' without having to re-build it; in which case you would 'hide'.
Without wanting to stress that topic to much, but I still stand with destroy never to be used with show. Destroy from a callback seems to break the cleanup that the DXL interpreter performs when a DXL program ends. That means that all data that is not explicitly freed (like skips, buffers, etc) will stay in memory when you destroy a showed dialog.
See here for an example:
https://www.ibm.com/developerworks/forums/thread.jspa?messageID=14629945�
Therefore leave it up to the DXL interpreter to free the dialog itself and only use hide to 'end' a 'show'n dialog (not destroy).
Regards, Mathias
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
|
|
Re: Multiple Dialog Box Confusion llandale - Sun Oct 16 17:24:18 EDT 2011 Mathias Mamsch - Sat Oct 15 06:25:01 EDT 2011
Darn, you are right ... It seems that you can end a blocked dialog with hide only from a callback that was registered by "ok(DB, ...)". Doing it from apply or a normal button callback does indeed freeze DOORS. That exception mislead me.
So what is the foolproof way to handle dialog boxes then? My suggestion would be to always do 'release x; hide x' in a callback to end a dialog. I know that it has redundancy in it, but I am thinking about all those people learning DXL having their dialogs freeze their DOORS client. So I will modify my suggestion for a best practice:
So I correct my suggested best-practices:
-
use 'release dbVar; hide dbVar' to end a dialog in callbacks
-
use 'block dbVar; destroy dbVar' for modal dialogs (i.e. the user cannot work in other windows)
-
use 'show dbVar' to show a non modal dialog
-
in more complex programs, introduce a cleanup method, which will close the dialog (by calling release, hide) and free any allocated ressources.
What do you think? I still think it is nice to have a unique way to handle 'show' and 'block'
Regards, Mathias
DB db
void clbkHideDBE(DBE dbXX) {
DB db = getParent dbXX
release db; hide(db)
}
void clbkHideDB(DB db) {
release db; hide(db)
}
db = create("Blocked Dialog")
ok (db, "OK close" , clbkHideDB)
apply (db, "Apply close" , clbkHideDB)
button(db, "Button Close", clbkHideDBE)
if (confirm "Show it?") {
show db
} else {
block db;
// evaluate dialog contents here ...
destroy db
}
Mathias Mamsch, IT-QBase GmbH, Consultant for Requirement Engineering and D00RS
Well, I hadn't thought about the "OK" button and don't think I've ever used it, but clearly it performs a "hide" for "show" dialogs and performs a "release" for "block" dialogs; as you suggest it probably mindlessly does both (where 'release' is ignored when it's 'shown' and 'hide' is redundant when it's 'blocked'). Just demonstrated that it indeed does NOT issue a "destroy" nor does it set the DB to null.
As a matter of opinion I don't see benefit in trying to write close callbacks that are independant from the method of displaying the dialog, but I'm sure that notion will grow on me some. It seems to me that shown dialogs are different beasts than blocked ones; I find it hard to imagine many dialogs and their callbacks and their close calllbacks that are conceptually identical and can seamlessly be switched between the two at the 'show' or 'block' command. 'block' seems to me for prompting for a small amount of information so the code can continue, or when you want to make sure that no module or other DB gets closed while the dialog is waiting for input. I suggest then that choosing 'block' is done for a reason that the code cares about. Analogy: I think Trucks are different beasts than Cars when it comes to driving them and they should have different manuals.
But otherwise your points look good. The only tiny issue is that those points fail to 'destroy' a 'shown' dialog which would only matter if you showed it 1,000 times. If you DID issue a destroy in a callback, then you have the timing problem outlined a few posts ago.
Is there a method to query if a DB variable is shown or blocked? If so, we can get even more carried away then we already have:
void clbkHideDB(DB db) {
release db; hide(db)
if (db is 'shown') then destroy(db)
}
I notice that setting "db = null" in these callbacks does NOT set the actual main variable to null, which is too bad since I use that to determine if the Dialog still exists and need ot be reconstructed. Thus, the callbacks set the main variable to null ignoring the input DB parameter.
|
|