Page history Edit this page How do I edit this website?
This page describes content relating to the Fiji distribution of ImageJ. Click the logo for details.

How to write custom actions for TrackMate

Introduction

Actions were my crude solution to the problem of adding random features to TrackMate without having to change the GUI too much. Adding buttons or dialogs or extra panels is cumbersome and I thought it would complexify the GUI, which is meant to be simple. A TrackMate action is a lazy workaround for this problem. You must keep in mind that is a placeholder for random feature ideas, and provided a quick and dirty way to test them.

A TrackMate action takes the shape of an item in a drop-down list in the last panel of the GUI. It can do more or less anything, since we pass everything to the action, even a reference to the GUI itself. Thanks to the SciJava discovery mechanism, we do not have to worry about adding it on the GUI: it will automatically be listed in the action list. The drawback of this simplicity is that you cannot use it to provide elaborated user interaction mechanisms, such as the ones you can find in a view.

In this tutorial, we will use it to launch the event logger we created in the previous tutorial of this series. If you remember, we saw in the last paragraph how to use the visible = false parameter the SciJava annotation to hide it from the view menu. Hereby preventing the user to access it. No problem, we will now build an action that will launch it as a supplementary view.

The TrackMateActionFactory interface

Again, the action behavior and its integration in TrackMate are split in two classes. The behavior is described by the TrackMateAction interface. The integration mechanism is controlled by the TrackMateActionFactory interface, which extends the TrackMateModule interface.

SciJava parameters recap

There is not much to say about the factory itself. It is the class that must be annotated with

@Plugin( type = TrackMateActionFactory.class )

All the SciJava annotation parameters apply, and they have the following meaning:

  • The enabled = true/false parameter is used to control whether the action is enabled or not. A disabled action is not even instantiated.
  • The visible = true/false parameter determines whether the action is listed in the action panel. If false, the action factory is instantiated but the corresponding action will not be listed in the panel, preventing any use.
  • The priority = double parameter is used here just to determine the order in which the action items appear in the list. High priorities are listed last.

Action factory methods

As of TrackMate version 7 (August 2021), actions are the only TrackMate modules that use the getIcon() method. The icon is then displayed in the action list, next to the action name. That’s it for the TrackMateModule part.

The method specific to actions is more interesting:

@Override
public TrackMateAction create()

This method does not have any parameter.

Important fields such as the model, etc., are passed to the action within the action class itself, but not in the factory

package plugin.trackmate.examples.action;

import javax.swing.ImageIcon;

import org.scijava.plugin.Plugin;

import fiji.plugin.trackmate.TrackMatePlugIn;
import fiji.plugin.trackmate.action.TrackMateAction;
import fiji.plugin.trackmate.action.TrackMateActionFactory;
import ij.ImageJ;
import ij.ImagePlus;

@Plugin( type = TrackMateActionFactory.class )
public class LaunchEventLoggerActionFactory implements TrackMateActionFactory
{

	private static final String INFO_TEXT = "<html>This action will launch a new event logger, that uses the ImageJ log window to append TrackMate events.</html>";

	private static final String KEY = "LAUNCH_EVENT_LOGGER";

	private static final String NAME = "Launch the event logger";

	@Override
	public String getInfoText()
	{
		return INFO_TEXT;
	}

	@Override
	public ImageIcon getIcon()
	{
		return null; // No icon for this one.
	}

	@Override
	public String getKey()
	{
		return KEY;
	}

	@Override
	public String getName()
	{
		return NAME;
	}

	@Override
	public TrackMateAction create()
	{
		return new LaunchEventLoggerAction();
	}
}

Nothing complicated.

The TrackMateAction interface

This interface is just made of two methods:

    public void execute( TrackMate trackmate, SelectionModel selectionModel, DisplaySettings displaySettings, Frame parent );
    
    public void setLogger(Logger logger);

The execute method is the one triggered by the user when he clicks the Execute button. It receives:

  • A TrackMate instance, containing the current model and the settings.
  • The selection model, currently used in the GUI.
  • The DisplaySettings currently used in the current views.
  • A Frame reference, if you need e.g. to make a modal dialog.
  • that can be of use. In our case, as you saw in the factory class, we got the model and selection model through the controller.

The other method is used to pass a logger instance that is specific to the action panel in the GUI. All messages and updates sent to this logger will be shown on the action panel.

Here is how this translates simply in a simple launcher:

package plugin.trackmate.examples.action;

import java.awt.Frame;

import fiji.plugin.trackmate.Logger;
import fiji.plugin.trackmate.SelectionModel;
import fiji.plugin.trackmate.TrackMate;
import fiji.plugin.trackmate.action.TrackMateAction;
import fiji.plugin.trackmate.gui.displaysettings.DisplaySettings;
import plugin.trackmate.examples.view.EventLoggerView;

public class LaunchEventLoggerAction implements TrackMateAction
{

	private Logger logger;

	@Override
	public void execute( final TrackMate trackmate, final SelectionModel selectionModel, final DisplaySettings displaySettings, final Frame parent )
	{
		logger.log( "Launching a new event logger..." );
		final EventLoggerView view = new EventLoggerView( trackmate.getModel(), selectionModel );
		view.render();
		logger.log( " Done.\n" );
	}

	@Override
	public void setLogger( final Logger logger )
	{
		this.logger = logger;
	}
}

Wrapping up

And here are the results:

/media/plugins/trackmate/trackmate-customaction-1.png

You can imagine a lot of applications for Actions. Since they give you access to most of the plugin context, you can basically plug anything there. The one limitation is that it does not fit perfectly in the existing GUI: actions just appear as items in a drop-down list. But in most cases it does not matter much. Actions are very useful to quickly graft a piece of new functionality on TrackMate.

This concludes this tutorial, which was pretty quick and simple. This is unfortunately the last time in this series that things are simple and short. The next tutorial will be about implementing a custom detector, which will turn to be quite complicated for apparently wrong reasons. See you there!