I am trying to create a simple user interface using GenericDialog. This is my first time using GenericDialog, and I'm having trouble. I would like to get input from the user, do some reality checks on the input, and then use it if it is valid or ask the user to correct the input if it is not valid. Below is a simplified version following the same logic I'm using:
import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.frame.*; import ij.IJ.*; import ij.ImagePlus.*; public class GenericDialog_Test extends PlugInFrame { public GenericDialog_Test() { super("Testing"); } public void run(String arg) { double width=0.0; double height=0.0; boolean validInputs = false; GenericDialog dialog = new GenericDialog("Input settings."); dialog.addNumericField("Width:", 50, 0); dialog.addNumericField("Height:", 100, 0); while (!validInputs) { validInputs = true; dialog.showDialog(); if (dialog.wasCanceled()) return; if (dialog.invalidNumber()) { IJ.showMessage("All inputs must be numbers. Please correct the inputs."); validInputs = false; continue; } width = dialog.getNextNumber(); if (width < 0.0) { validInputs = false; IJ.showMessage("The width must be positive."); } height = (int)dialog.getNextNumber(); if (height < 0.0) { validInputs = false; IJ.showMessage("The height must be positive."); } } //Of course, here I would call a function to do calculations instead of just redisplaying the inputs. IJ.showMessage("Inputs were " + width + ", " + height); return; } } When I run the code, one of three things happens. 1) I put in valid numbers, and everything is fine--I get the "Inputs were..." message with my data in it. 2) I type in something which isn't a number, like "xyz" into one of the fields. For the sake of this illustration, let's say it was the width field. What I'm hoping for is the error message "All inputs...", then for the "Input Settings" dialog to reappear, so I can try again. What I get is "Inputs were 0, 100". If I understand the purpose of validInputs() correctly, this appears to be a bug. 3) I type in a number, but one which is unacceptable. Let's say I set width to -1. What I hope for is for the error message "The width...", followed by the "Input Settings" dialog to reappear, so I can try again. It does reappear, and allows me to make corrections to the width and height fields, but both the OK and Cancel buttons are unresponsive. My only way forward at this point is to kill the window with the x in the upper right hand corner. How do I correct this? Thanks |
On Monday 25 Apr 2011 22:23:28 Bob Loushin <[hidden email]> wrote:
> I am trying to create a simple user interface using GenericDialog. This is > my first time using GenericDialog, and I'm having trouble. I am not sure this is the proper way to do it, but it seems to work. Cheers Gabriel import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.frame.*; import ij.IJ.*; import ij.ImagePlus.*; public class GenericDialog_Test extends PlugInFrame { public GenericDialog_Test() { super("Testing"); } public void run(String arg) { double width=0.0; double height=0.0; boolean validInputs = false; while (!validInputs) { GenericDialog dialog = new GenericDialog("Input settings."); dialog.addNumericField("Width:", 50, 0); dialog.addNumericField("Height:", 100, 0); validInputs = true; dialog.showDialog(); if (dialog.wasCanceled()) return; width = dialog.getNextNumber(); if (width < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Width is Invalid."); } height = (int)dialog.getNextNumber(); if (height < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Height is Invalid."); } } //Of course, here I would call a function to do calculations IJ.showMessage("Inputs were " + width + ", " + height); return; } } |
In reply to this post by Bob Loushin
Thank you, Gabriel. The idea of throwing out the old dialog which doesn't work and creating a new, identical one each time through the loop is an effective work-around, although I agree with you, probably not "proper". However, the nonworking invalidNumber() method is still an issue--unlike my stripped down example, in my actual application, 0.0 is a valid response for some of the parameters.
At this point, I'm hoping that the ImageJ gods will decide it's a bug and fix it, but there is still the possibility that I'm doing something wrong. The application will still run fine, it just won't have as much protection from user typos as I'd hoped. I forgot to mention versioning in my first post. I'm running a relatively recent version, 1.45a, but I could try an upgrade to see if that helps. Bob ----- Original Message ----- From: "Gabriel Landini" <[hidden email]> To: [hidden email] Sent: Monday, April 25, 2011 6:58:02 PM Subject: Re: GenericDialog On Monday 25 Apr 2011 22:23:28 Bob Loushin <[hidden email]> wrote: > I am trying to create a simple user interface using GenericDialog. This is > my first time using GenericDialog, and I'm having trouble. I am not sure this is the proper way to do it, but it seems to work. Cheers Gabriel import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.frame.*; import ij.IJ.*; import ij.ImagePlus.*; public class GenericDialog_Test extends PlugInFrame { public GenericDialog_Test() { super("Testing"); } public void run(String arg) { double width=0.0; double height=0.0; boolean validInputs = false; while (!validInputs) { GenericDialog dialog = new GenericDialog("Input settings."); dialog.addNumericField("Width:", 50, 0); dialog.addNumericField("Height:", 100, 0); validInputs = true; dialog.showDialog(); if (dialog.wasCanceled()) return; width = dialog.getNextNumber(); if (width < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Width is Invalid."); } height = (int)dialog.getNextNumber(); if (height < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Height is Invalid."); } } //Of course, here I would call a function to do calculations IJ.showMessage("Inputs were " + width + ", " + height); return; } } |
> At this point, I'm hoping that the ImageJ gods will decide it's a bug
> and fix it, but there is still the possibility that I'm doing > something wrong. The application will still run fine, it just won't > have as much protection from user typos as I'd hoped. One approach that might help is to attach a DialogListener and parse each String / number field using Java's built in String and Double methods. Michael |
In reply to this post by Bob Loushin
Well, I did some more digging, and here's what I found out.
I usually use three references for writing plugins, both from the ImageJ website. The ImageJ plugin tutorial by Werner Bailer basically mentions invalidNumber() and says to call it to check if the numbers returned are actually valid numbers. And the free appendix from Burger and Burge gives a code example, a piece of which I copy here (but the text reproduction is going to mangle the formatting): 42 GenericDialog dlg = new GenericDialog("Harris Corner Detector", IJ.getInstance()); 43 float def_alpha = HarrisCornerDetector.DEFAULT_ALPHA; 44 dlg.addNumericField("Alpha (default: "+def_alpha+")", alpha, 3); 45 int def_threshold = HarrisCornerDetector. DEFAULT_THRESHOLD; 46 dlg.addNumericField("Threshold (default: "+def_threshold+ ")", threshold, 0); 47 dlg.addNumericField("Max. points (0 = show all)", nmax, 0); 48 dlg.showDialog(); 49 if(dlg.wasCanceled()) 50 return false; 51 if(dlg.invalidNumber()) { 52 IJ.showMessage("Error", "Invalid input number"); 53 return false; 54 } 55 alpha = (float) dlg.getNextNumber(); 56 threshold = (int) dlg.getNextNumber(); 57 nmax = (int) dlg.getNextNumber(); The numbers are line numbers from their code. Clearly, they have the call to invalidNumber() BEFORE calls to getNextNumber(). Finally, I looked at the ImageJ API documentation. All it says is " Returns true if one or more of the numeric fields contained an invalid number." But this pattern doesn't work. Digging through the code base, I found that the check for validity is actually performed in getNextNumber(). As far as I can tell, if it tries to read something which isn't a number, it internally ends up with a double having the value NaN. It then checks to see if it is NaN, and if it is, it sets a flag and CHANGES THE VALUE OF THE NUMBER READ from NaN to 0.0. All invalidNumber() does is read the flag. So for invalidNumber() to work, it has to be called AFTER all calls to getNextNumber() are complete, otherwise it has no way to know if one of the numbers is invalid. So moving the check for invalidNumber to the end of the while loop instead of the beginning works. To me, this is counter intuitive. I usually try to check for invalid input before converting it, rather than converting it first and checking later. I'd like to suggest two changes. First, make it clear in the API documentation that all calls to getNextNumber() need to be done before the call to invalidNumber(). Second, if the value comes out NaN, leave it as NaN instead of changing it to 0.0. My understanding is that Java math is supposed to be able to cope with it for all calculations, and any calculation done with NaN returns NaN. This will be clearly identifiable as wrong. By just changing it to 0.0, the results are also wrong, but it may not be so easy to spot. Thanks, Bob ----- Original Message ----- From: "Bob Loushin" <[hidden email]> To: [hidden email] Sent: Tuesday, April 26, 2011 9:19:47 AM Subject: Re: GenericDialog Thank you, Gabriel. The idea of throwing out the old dialog which doesn't work and creating a new, identical one each time through the loop is an effective work-around, although I agree with you, probably not "proper". However, the nonworking invalidNumber() method is still an issue--unlike my stripped down example, in my actual application, 0.0 is a valid response for some of the parameters. At this point, I'm hoping that the ImageJ gods will decide it's a bug and fix it, but there is still the possibility that I'm doing something wrong. The application will still run fine, it just won't have as much protection from user typos as I'd hoped. I forgot to mention versioning in my first post. I'm running a relatively recent version, 1.45a, but I could try an upgrade to see if that helps. Bob ----- Original Message ----- From: "Gabriel Landini" <[hidden email]> To: [hidden email] Sent: Monday, April 25, 2011 6:58:02 PM Subject: Re: GenericDialog On Monday 25 Apr 2011 22:23:28 Bob Loushin <[hidden email]> wrote: > I am trying to create a simple user interface using GenericDialog. This is > my first time using GenericDialog, and I'm having trouble. I am not sure this is the proper way to do it, but it seems to work. Cheers Gabriel import ij.*; import ij.process.*; import ij.gui.*; import java.awt.*; import ij.plugin.frame.*; import ij.IJ.*; import ij.ImagePlus.*; public class GenericDialog_Test extends PlugInFrame { public GenericDialog_Test() { super("Testing"); } public void run(String arg) { double width=0.0; double height=0.0; boolean validInputs = false; while (!validInputs) { GenericDialog dialog = new GenericDialog("Input settings."); dialog.addNumericField("Width:", 50, 0); dialog.addNumericField("Height:", 100, 0); validInputs = true; dialog.showDialog(); if (dialog.wasCanceled()) return; width = dialog.getNextNumber(); if (width < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Width is Invalid."); } height = (int)dialog.getNextNumber(); if (height < 0.0 || dialog.invalidNumber() ) { validInputs = false; IJ.showMessage("Height is Invalid."); } } //Of course, here I would call a function to do calculations IJ.showMessage("Inputs were " + width + ", " + height); return; } } |
In reply to this post by Bob Loushin
Hello Bob,
I added a call to dialog.pack() in your original code and the problem appears to be gone, that is, ... dialog.pack(); dialog.showDialog(); ... The dialog is created only once. Highly experimental and I am not sure why and if this is "proper". --Wilhelm > -----Original Message----- > From: ImageJ Interest Group [mailto:[hidden email]] On Behalf Of > Bob Loushin > Sent: Tuesday, April 26, 2011 4:20 PM > To: [hidden email] > Subject: Re: GenericDialog > > Thank you, Gabriel. The idea of throwing out the old dialog which > doesn't work and creating a new, identical one each time through the > loop is an effective work-around, although I agree with you, probably > not "proper". However, the nonworking invalidNumber() method is still > an issue--unlike my stripped down example, in my actual application, > 0.0 is a valid response for some of the parameters. > > At this point, I'm hoping that the ImageJ gods will decide it's a bug > and fix it, but there is still the possibility that I'm doing something > wrong. The application will still run fine, it just won't have as much > protection from user typos as I'd hoped. > > I forgot to mention versioning in my first post. I'm running a > relatively recent version, 1.45a, but I could try an upgrade to see if > that helps. > > Bob > > ----- Original Message ----- > From: "Gabriel Landini" <[hidden email]> > To: [hidden email] > Sent: Monday, April 25, 2011 6:58:02 PM > Subject: Re: GenericDialog > > On Monday 25 Apr 2011 22:23:28 Bob Loushin <[hidden email]> > wrote: > > I am trying to create a simple user interface using GenericDialog. > This is > > my first time using GenericDialog, and I'm having trouble. > > I am not sure this is the proper way to do it, but it seems to work. > Cheers > > Gabriel > > > import ij.*; > import ij.process.*; > import ij.gui.*; > import java.awt.*; > import ij.plugin.frame.*; > import ij.IJ.*; > import ij.ImagePlus.*; > > public class GenericDialog_Test extends PlugInFrame { > > public GenericDialog_Test() { > super("Testing"); > } > > public void run(String arg) { > double width=0.0; > double height=0.0; > boolean validInputs = false; > > while (!validInputs) { > GenericDialog dialog = new GenericDialog("Input settings."); > > dialog.addNumericField("Width:", 50, 0); > dialog.addNumericField("Height:", 100, 0); > validInputs = true; > dialog.showDialog(); > > if (dialog.wasCanceled()) return; > > width = dialog.getNextNumber(); > if (width < 0.0 || dialog.invalidNumber() ) { > validInputs = false; > IJ.showMessage("Width is Invalid."); > } > > height = (int)dialog.getNextNumber(); > if (height < 0.0 || dialog.invalidNumber() ) { > validInputs = false; > IJ.showMessage("Height is Invalid."); > } > } > > //Of course, here I would call a function to do calculations > IJ.showMessage("Inputs were " + width + ", " + height); > return; > } > } |
In reply to this post by Bob Loushin
On Tuesday 26 Apr 2011, you wrote:
> However, the nonworking invalidNumber() method is still an issue Sorry I do not get it. Can you please show an example when it does not work? If you put a letter instead of a number, the invalidNumber is true. > --unlike > my stripped down example, in my actual application, 0.0 is a valid > response for some of the parameters. As I understand it, you need to check invalidNumber each time you get value from the dialog, and if it not invalid, then check if it is in the range of values you want. The way you were doing it could not tell if the first number was invalid when the second number was not because you called invalidNumber after all the values were were obtained. > At this point, I'm hoping that the ImageJ gods will decide it's a bug and > fix it, I am not sure I understandt the problem... What values fail to be detected as invalid with the plugin modification I sent? Cheers G. |
Gabriel,
Yes, you're right--what you posted does work. When I wrote that, I was still hung up on the idea that the invalidNumber() test should come before one tries to read the number, rather than after. I still hadn't realized that it didn't always failed. In a post I wrote since then, I realized that though it wasn't documented, invalidNumber() has to come after the getNextNumber() call, as you have it, and that it does work then. I still think, though, that the fact that getNextNumber() returns 0.0 instead of NaN when the input isn't a number is a bug that should be fixed. Bob ----- Original Message ----- From: "Gabriel Landini" <[hidden email]> To: [hidden email] Sent: Tuesday, April 26, 2011 10:55:19 AM Subject: Re: GenericDialog On Tuesday 26 Apr 2011, you wrote: > However, the nonworking invalidNumber() method is still an issue Sorry I do not get it. Can you please show an example when it does not work? If you put a letter instead of a number, the invalidNumber is true. > --unlike > my stripped down example, in my actual application, 0.0 is a valid > response for some of the parameters. As I understand it, you need to check invalidNumber each time you get value from the dialog, and if it not invalid, then check if it is in the range of values you want. The way you were doing it could not tell if the first number was invalid when the second number was not because you called invalidNumber after all the values were were obtained. > At this point, I'm hoping that the ImageJ gods will decide it's a bug and > fix it, I am not sure I understandt the problem... What values fail to be detected as invalid with the plugin modification I sent? Cheers G. |
On Apr 26, 2011, at 1:28 PM, Bob Loushin wrote:
> Gabriel, > > Yes, you're right--what you posted does work. When I wrote that, I was still hung up on the idea that the invalidNumber() test should come before one tries to read the number, rather than after. I still hadn't realized that it didn't always failed. In a post I wrote since then, I realized that though it wasn't documented, invalidNumber() has to come after the getNextNumber() call, as you have it, and that it does work then. I still think, though, that the fact that getNextNumber() returns 0.0 instead of NaN when the input isn't a number is a bug that should be fixed. In the ImageJ 1.45g daily build, GenericDialog.getNextNumber() returns NaN when the input is not a number. Here is an example macro that tests for NaN to insure that the numeric input is valid: requires("1.45g"); do { Dialog.create("Test"); Dialog.addNumber("Width:", 512); Dialog.addNumber("Height:", 512); Dialog.show(); width = Dialog.getNumber(); height = Dialog.getNumber();; } while (isNaN(width)||isNaN(height)); print(width, height); And here is an example plugin that uses the GenericDialog.invalidNumber() to insure that numeric input is valid: import ij.*; import ij.gui.*; import ij.plugin.*; public class Dialog_Test implements PlugIn { public void run(String arg) { double width, height; GenericDialog gd; do { gd = new GenericDialog("Test"); gd.addNumericField("Width:", 512, 0); gd.addNumericField("Height:", 512, 0); gd.showDialog(); width = gd.getNextNumber(); height = gd.getNextNumber();; } while (gd.invalidNumber()&&!gd.wasCanceled()); if (!gd.wasCanceled()) IJ.log("width="+width+", height="+height); } } -wayne > ----- Original Message ----- > From: "Gabriel Landini" <[hidden email]> > To: [hidden email] > Sent: Tuesday, April 26, 2011 10:55:19 AM > Subject: Re: GenericDialog > > On Tuesday 26 Apr 2011, you wrote: >> However, the nonworking invalidNumber() method is still an issue > > Sorry I do not get it. Can you please show an example when it does not work? > > If you put a letter instead of a number, the invalidNumber is true. > >> --unlike >> my stripped down example, in my actual application, 0.0 is a valid >> response for some of the parameters. > > As I understand it, you need to check invalidNumber each time you get value > from the dialog, and if it not invalid, then check if it is in the range of > values you want. > The way you were doing it could not tell if the first number was invalid when > the second number was not because you called invalidNumber after all the > values were were obtained. > >> At this point, I'm hoping that the ImageJ gods will decide it's a bug and >> fix it, > > I am not sure I understandt the problem... > What values fail to be detected as invalid with the plugin modification I > sent? > > Cheers > > G. |
In reply to this post by Bob Loushin
Hi Bob,
one more (and very simple) way of checking the input of a GenericDialog: Have a DialogListener, and return false if the user enters invalid input. Code example: (extracted from the Fast_Filters plugin) GenericDialog gd = new GenericDialog(command+"..."); gd.addNumericField("x Radius", xRadius, 0); gd.addNumericField("y Radius", yRadius, 0); gd.addDialogListener(this); // the DialogItemChanged method will be called on user input gd.showDialog(); ... public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) { xRadius = (int)gd.getNextNumber(); yRadius = (int)gd.getNextNumber(); return (!gd.invalidNumber() && xRadius>=0 && yRadius>=0 && xRadius<1000000 && yRadius<1000000); It won't tell the user which value is incorrect and why, just that the 'OK' button gets disabled if the input is incorrect. For a verbose output: You could add a message to the dialog, and in the dialogItemChanged method you can write an error message to that message field. If you do this, note that there is a stupid bug on Mac OS X, which often disables multiple changes in a dialog if they happen within short time (in this case, changing the OK button and the message). This could be prevented by adding an IJ.wait(100) statement between setting the message text and returning the boolean (no typical user will type more than 10 characters per second, so no one will feel that delay, I guess?) Michael ________________________________________________________________ On 26 Apr 2011, at 19:28, Bob Loushin wrote: > Gabriel, > > Yes, you're right--what you posted does work. When I wrote that, I > was still hung up on the idea that the invalidNumber() test should > come before one tries to read the number, rather than after. I > still hadn't realized that it didn't always failed. In a post I > wrote since then, I realized that though it wasn't documented, > invalidNumber() has to come after the getNextNumber() call, as you > have it, and that it does work then. I still think, though, that > the fact that getNextNumber() returns 0.0 instead of NaN when the > input isn't a number is a bug that should be fixed. > > Bob > > ----- Original Message ----- > From: "Gabriel Landini" <[hidden email]> > To: [hidden email] > Sent: Tuesday, April 26, 2011 10:55:19 AM > Subject: Re: GenericDialog > > On Tuesday 26 Apr 2011, you wrote: >> However, the nonworking invalidNumber() method is still an issue > > Sorry I do not get it. Can you please show an example when it does > not work? > > If you put a letter instead of a number, the invalidNumber is true. > >> --unlike >> my stripped down example, in my actual application, 0.0 is a valid >> response for some of the parameters. > > As I understand it, you need to check invalidNumber each time you > get value > from the dialog, and if it not invalid, then check if it is in the > range of > values you want. > The way you were doing it could not tell if the first number was > invalid when > the second number was not because you called invalidNumber after > all the > values were were obtained. > >> At this point, I'm hoping that the ImageJ gods will decide it's a >> bug and >> fix it, > > I am not sure I understandt the problem... > What values fail to be detected as invalid with the plugin > modification I > sent? > > Cheers > > G. |
In reply to this post by Bob Loushin
Thank you, Wayne, for changing this.
Also thanks to Michael Schmid, Michael Doube, and Wilhelm Burger for suggesting alternatives. And finally, thank you Gabriel for publishing example code that got me around my problems. Bob ----- Original Message ----- From: "Wayne Rasband (NIH/NIMH) [E]" <[hidden email]> To: [hidden email] Sent: Wednesday, April 27, 2011 12:13:54 AM Subject: Re: GenericDialog On Apr 26, 2011, at 1:28 PM, Bob Loushin wrote: > Gabriel, > > Yes, you're right--what you posted does work. When I wrote that, I was still hung up on the idea that the invalidNumber() test should come before one tries to read the number, rather than after. I still hadn't realized that it didn't always failed. In a post I wrote since then, I realized that though it wasn't documented, invalidNumber() has to come after the getNextNumber() call, as you have it, and that it does work then. I still think, though, that the fact that getNextNumber() returns 0.0 instead of NaN when the input isn't a number is a bug that should be fixed. In the ImageJ 1.45g daily build, GenericDialog.getNextNumber() returns NaN when the input is not a number. Here is an example macro that tests for NaN to insure that the numeric input is valid: requires("1.45g"); do { Dialog.create("Test"); Dialog.addNumber("Width:", 512); Dialog.addNumber("Height:", 512); Dialog.show(); width = Dialog.getNumber(); height = Dialog.getNumber();; } while (isNaN(width)||isNaN(height)); print(width, height); And here is an example plugin that uses the GenericDialog.invalidNumber() to insure that numeric input is valid: import ij.*; import ij.gui.*; import ij.plugin.*; public class Dialog_Test implements PlugIn { public void run(String arg) { double width, height; GenericDialog gd; do { gd = new GenericDialog("Test"); gd.addNumericField("Width:", 512, 0); gd.addNumericField("Height:", 512, 0); gd.showDialog(); width = gd.getNextNumber(); height = gd.getNextNumber();; } while (gd.invalidNumber()&&!gd.wasCanceled()); if (!gd.wasCanceled()) IJ.log("width="+width+", height="+height); } } -wayne > ----- Original Message ----- > From: "Gabriel Landini" <[hidden email]> > To: [hidden email] > Sent: Tuesday, April 26, 2011 10:55:19 AM > Subject: Re: GenericDialog > > On Tuesday 26 Apr 2011, you wrote: >> However, the nonworking invalidNumber() method is still an issue > > Sorry I do not get it. Can you please show an example when it does not work? > > If you put a letter instead of a number, the invalidNumber is true. > >> --unlike >> my stripped down example, in my actual application, 0.0 is a valid >> response for some of the parameters. > > As I understand it, you need to check invalidNumber each time you get value > from the dialog, and if it not invalid, then check if it is in the range of > values you want. > The way you were doing it could not tell if the first number was invalid when > the second number was not because you called invalidNumber after all the > values were were obtained. > >> At this point, I'm hoping that the ImageJ gods will decide it's a bug and >> fix it, > > I am not sure I understandt the problem... > What values fail to be detected as invalid with the plugin modification I > sent? > > Cheers > > G. |
Free forum by Nabble | Edit this page |