Generic dialog

Revision as of 11:57, 6 June 2019 by Rueden (talk | contribs) (Link to ImageJ1 page)

Introduction

The Generic Dialog class is part of ImageJ1 and can be used to make simple graphical user interfaces for scripts and plugins. It requires a bit more of work than with the script parameters option but offers more possibilities.
Fiji offers an additional GenericDialogPlus subclass which include additional GUI item like a file input with a browse button.
Like the script parameters, plugins using the Generic Dialog (or one of its subclass) are macro recordable.

Here is an example in Jython.

from ij.gui import GenericDialog

# Create an instance of GenericDialog
GUI = GenericDialog("My first GUI")

# Add some GUI elements (Ok and Cancel button are present by default)
# Elements are stacked on top of each others by default (unless specified)
GUI.addMessage("Some information to display at the top of the GUI")
GUI.addStringField("Type some input text :", "initial text")
GUI.addCheckbox("This is a tickbox->Activate some option", True)

# We can add elements next to each other using the addToSameRow method
GUI.addToSameRow() # The next item is appended next to the tick box
GUI.addChoice("Choose one option among a list", ["Choice1", "Choice2"], "Choice1") # Choice1 is default here

GUI.addNumericField("Some integer", 10, 0) # 0 for no decimal part

# Add a Help button in addition to the default OK/Cancel
GUI.addHelp(r"https://imagej.net/Generic_dialog") # clicking the help button will open the provided URL in the default browser

# Show dialog, the rest of the code is not executed before OK or Cancel is clicked
GUI.showDialog() # dont forget to actually display the dialog at some point


# If the GUI is closed by clicking OK, then recover the inputs in order of "appearance"
if GUI.wasOKed():
    inString = GUI.getNextString()
    inBool = GUI.getNextBoolean()
    inChoice = GUI.getNextChoice() # one could alternatively call the getNextChoiceIndex too
    inNum = Win.getNextNumber() # This always return a double (ie might need to cast to int)

Image and file inputs

By default, script and plugins process the last selected image.
However sometime one needs to specify different images or files as input.
The subclass GenericDialogPlus provides a couple of handful methods for such cases, while all methods shown above are inherited from the GenericDialog class.

from fiji.util.gui import GenericDialogPlus

# Create an instance of GenericDialogPlus
GUI = GenericDialogPlus("an enhanced GenericDialog")

# Add possibility to choose some images already opened in Fiji
GUI.addImageChoice("Image1","Some description for image1")
GUI.addImageChoice("Image2","Some description for image2")


# The GenericDialogPlus also allows to select files, folder or both using a browse button
GUI.addFileField("Some_file path", "DefaultFilePath")
GUI.addDirectoryField("Some_folder path", "DefaultFolderPath")
GUI.addDirectoryOrFileField("Some_Path", "DefaultPath")

GUI.showDialog()

# Recover the inputs in order of "appearance"
if GUI.wasOKed():
    ImpImage1 = GUI.getNextImage() # This method directly returns the ImagePlus object
    ImpImage2 = GUI.getNextImage()
    
    # Path are recovered as string
    FilePath   = GUI.getNextString()
    FolderPath = GUI.getNextString()
    SomePath   = GUI.getNextString()

Macro-recording

Just like script parameters, plugins using the GenericDialog class are macro-recordable.
One important thing to note is the name of the variable in the recorded command. This name is actually the first word of the string used as label for each item, with lowercase letters only.
A single word is not very intuitive to understand a parameter in most cases. To include the next words of the label in the recorded command replace the space with underscores, as in some_file above.

For instance the previous code saved as GUI_.py in Fiji.app/scripts/Plugins/Test yields the following recorded command:

run("GUI ", "image1=MyImage1.tif image2=MyImage2.tif some_file=DefaultFilePath some_folder=DefaultFolderPath some_path=DefaultPath");

Recalling previous entries using the PrefService

It is convenient to have the previously entered parameters recalled at the next run of a given plugin. This is happening automatically for Script parameters (unless specified differently) but not for the GenericDialog class.
Fortunately, it is still possible to make it works using the PrefService.

Services are some ImageJ2/SciJava features that can be though as some kind of package import at runtime. Here the link to the PrefService Javadoc.
And below is a Jython example of how to use it.

#@PrefService prefs 
from fiji.util.gui import GenericDialogPlus 
 
# Create GUI 
Win = GenericDialogPlus("Some GUI")
 
Win.addImageChoice("Image", prefs.get(None, "Image", "DefaultImage") ) 
Win.addCheckbox("Activate some option", prefs.getInt(None, "doOption", False) ) # in theory we should use the getBoolean method but it does not work for Jython, the wrong method signature is matched
Win.addStringField("Some_string", prefs.get(None, "someString", "initial")) 
Win.addChoice("Some_choice", ["Choice1","Choice2"], prefs.get(None, "someChoice", "DefaultChoice")) 
Win.addNumericField("Some_integer", prefs.getInt(None, "N", 1), 0)  
Win.addNumericField("Some_float", prefs.getFloat(None, "Decimal", 0.5), 2) 
 
Win.showDialog() 
 
if Win.wasOKed(): 
	image      = Win.getNextImage() 
	doOption   = Win.getNextBoolean()
	someString = Win.getNextString() 
	someChoice = Win.getNextChoice() 
	N          = int(Win.getNextNumber()) # cast to int : getNextNumber always return a double
	Decimal = Win.getNextNumber()
	 
	# Save in memory using PrefService 
	prefs.put(None, "Image", image.getTitle()) 
	prefs.put(None, "doOption", doOption) 
	prefs.put(None, "someString", someString) 
	prefs.put(None, "someChoice", someChoice ) 
	prefs.put(None, "N", N) 
	prefs.put(None, "Decimal", Decimal) 

The first step is to "import" the PrefService and to assign it a name, here prefs.

Then there are 2 methods to respectively recover and store some parameter values from the PrefService, namely get and put.

Let's start with get. This method is define for the different datatype getInt, getFloat, getBoolean. An exception for String there is no getString just get.
Also in Jython the getBoolean method is not mapping the right Java signature, so use getInt instead as illustrated above.

There are 3 arguments for the get methods:

- the 1st one is the Plugin class for which to associate the parameter persistence. Leave it None (or Null in other languages) to use the default.

- the 2nd argument is the name of the variable to recall from memory/the preferences, it should be the same name used by the put method for that parameter.

- the last parameter is the default value to use if no variable with such name exist in memory ie the first time you run your script or if you reset the preferences.


The method put is even simpler as there is only a single method that takes also 3 arguments:

- The 1st is like for get an optional Plugin class

- The 2nd argument is the name used to store the parameter value in memory/in the preferences, it is the same name used by get to recover the previously entered value.

- The 3rd value is the value to store in memory with the name in argument 2. If the parameter was already existing in memory the value is updated to this newly provided value.

Therefore in the script above, the default values for the GenericDialog fields are initialized to the values available in memory, or some default values if there are missing in memory.
Once the GUI is oked, the values in memory are updated with the newly typed values, using the put method.

Custom buttons

TO DO