Non-blocking (non-modal) IJ2 plugin dialog

imagej2
scijava
Tags: #<Tag:0x00007fa307633f88> #<Tag:0x00007fa307633e48>

#1

@stelfrich @imagejan
Is it possible to have the IJ2 auto-generated plugin dialog “non-modal”?
For my use case the user must still be able to interact with the sliders in the Hyperstack viewer to be able to set sensible GUI parameters.


#2

I guess you are looking for Interactive. Making your Command implement it should actually be enough.

Best,
Stefan


#3

Thanks, @stelfrich, for pointing at this. I’ve actually never tried this one.

I it makes me think of two follow-up questions:

  • Is it possible to make a script interactive as well? If not, would it be possible/desirable to add a script directive (or improve the #@script directive) to support this case?

  • The javadoc states:

    … with Module#run() being called whenever any of the values change.

    Is there a possibility (e.g by annotation) to disable auto-running upon change of input values (either globally, or per input item) and instead generate an Update button to trigger re-calculation? This might be useful for computationally heavy processing that still should be interactive in the above sense.


#4

Thanks! That indeed works! However implementing Interactive makes it immediately execute the run( ) method. After that, the GUI stays open and is responsive, but I tested it in debug mode and changing any of the GUI elements does not seem to cause the run( ) method to be executed again…

Do you know example code where Interactive is used such that I could learn from this?


#5

Via http://search.imagej.net/, I found the following classes that extend InteractiveCommand:


#6

^ This is good to know!

And regarding the usage of Interactive it looks like that the run method is not so important but the idea rather is that there are buttons with callbacks and then inside the callback functions you retrieve the current state of the user input. Makes sense!


#7

@stelfrich, @ctrueden
Do you also know how such an Interactive Command behaves when being called from command line? As the run method is not really useful anymore one should probably somehow tell it which (callback) method to execute?

And, related to that, somehow it feels a bit complex to add callback buttons and methods just be to be able to still interact with the currently open images. Isn’t there maybe an easier way to make a Command non-blocking while still preserving the normal Command logic.


#8

An InteractiveCommand (or InteractiveImageCommand) is still a SciJava Command, so as long as the run() method implements something useful (and it should do so, IMHO, instead of delegating everything to the callback methods – but that’s up to the implementer), I suppose you should be able to run it headless as well.

You don’t have to implement callback buttons, do you? You can just take it as a non-modal dialog, and do the processing as usual, no? Or maybe am I misunderstanding something here?


#9

When I run below main method, it logs two times “Run”, only then it shows the GUI and when I click the Run button it prints “Execute”. This looks to me as if the run method is used as some kind of initializer?! Or am I doing something wrong here in my code?

@Plugin( type = InteractiveCommand.class )
public class TestInteractiveCommand extends InteractiveCommand
{
	@Parameter( label = "Run", callback = "execute" )
	private Button runButton;

	public void run()
	{
		IJ.log( "Run" );
	}


	public void execute()
	{
		IJ.log( "Execute" );
	}

	public static void main(final String... args) throws Exception
	{
		final ImageJ ij = new ImageJ();
		ij.ui().showUI();

		// invoke the plugin
		ij.command().run( TestInteractiveCommand.class, true );
	}
	
}

#10

Seems like run() gets called the first time when the panel is built and a second time during the preprocessing of the module… Not super intuitive, but intended I guess?

Here is an example (IJ2 style) how you could run the execute() method from run() when you are in headless mode. Did not try it from a script but I guess it should work.


import net.imagej.ImageJ;
import org.scijava.command.InteractiveCommand;
import org.scijava.plugin.Parameter;
import org.scijava.plugin.Plugin;
import org.scijava.widget.Button;

@Plugin( type = InteractiveCommand.class, headless = true )
public class TestInteractiveCommand extends InteractiveCommand
{
	@Parameter( label = "Run", callback = "execute" )
	private Button runButton;

	@Parameter
	private ImageJ ij;

	public void run()
	{
		ij.log().info( "Run" );
		if(ij.ui().isHeadless()){
			execute();
		}
	}


	public void execute()
	{
		ij.log().info( "Execute" );
	}

	public static void main(final String... args) throws Exception
	{
		final ImageJ ij = new ImageJ();
		ij.ui().setHeadless(true);
//		ij.ui().showUI();

		// invoke the plugin
		ij.command().run( TestInteractiveCommand.class, true );
	}
	
}

#11

Yes, from the javadoc of Interactive (emphasis added):

Typically this means its inputs are supposed to be presented in a non-modal dialog box, with Runnable.run() being called whenever any of the values change.

This means that (unlike the “non-interactive” DynamicCommand) you don’t even need to use any callbacks here, right?

Rather than checking for isHeadless() and creating two different code paths, I’d suggest to instead implement some checks that - when in interactive mode - only do the computations made necessary by the parameters that changed between two subsequent runs.


#12

The confusing part might be that there is only one value (the button) which is not changed from user or plugin side but the run-method is still called twice before the dialog even pops up.

I understood that @Christian_Tischer wants some kind of final action that can be started by clicking a “Run” - button in the GUI (since the initial question was only how to make the dialog non-modal). That’s why there is this additional execute-function in his code that would listen to the button in the GUI and could be called automatically in headless mode.


#13

I would advise against using InteractiveCommand for headless and command line commands. Instead, write a “low-level” command that takes a fixed set of inputs, and is usable headless from the CLI etc. Then write a “high-level” InteractiveCommand wrapper that has nicer behavior for users in the GUI, and delegates to the lower-level command (or static utility method shared by both commands) as needed. This two-level pattern is very useful in many cases, and avoids conflating too many conflicting requirements into a single command.


#14

Thank you very much for the advise!

More in general I was now wondering: Typically when you run an IJ2 plugin (Command) you have enter some parameters. And again, typically, to enter sensible parameters you have to look at the image, which involves changing brightness and contrast, moving around in z a.s.o.

So I wonder whether it would make sense that the default behavior for
@Plugin( type = Command.class )
when invoked from the UI should be to be “non-blocking”, i.e. allow interaction with the currently open image(s)?!

Technically I guess it would mean starting the plugin in an own thread and not blocking the main UI thread, is this right?

Like here: