Creating extensions
QuPath extensions provide a way to add extra functionality to the main QuPath GUI without having to modify the existing code.
Extensions are written in Java and distributed as Jar files. Unlike scripts, extensions can be used to manipulate QuPath in almost any way - including replacing or removing some of the built-in tools or functionality. As such, extensions can achieve a lot more than scripts... but are a bit more complicated to create.
Extensions are simply Jar files that sit somewhere on QuPath's classpath - generally in a extensions directory (for an optional extension), or along with the other main QuPath application files (for a built-in extension, which is part of the 'standard' QuPath distribution).
If you are familiar with ImageJ, extensions are a bit like plugins - but not quite the same. While plugins are generally used to add one or more processing commands within ImageJ, an extension can transform QuPath in a much more flexible way.
During startup, QuPath will check its classpath to find out what extensions are available - and then install each of them in turn.
The order in which extensions are installed is undefined (i.e. best to consider it random), but it is assured that each extension will only be installed once.
To install an extension, a user generally only needs to do two things:
- Drag one or more Jar files containing the extension onto QuPath
- Create a extensions directory if one does not already exist, or accept the default
QuPath will then proceed to copy the Jars into the directory, and try to install the extension immediately. QuPath will also automatically install the extension - along with any others in the extensions directory - the next time it is started up.
The extensions directory can be changed later inside the Preferences panel.
Removing an extension simply involves going to the extensions directory and removing the related Jar files. It is necessary to restart QuPath for this to take effect.
Creating a new QuPath extension involves three main steps:
- Write a Java class that implements the interface
qupath.lib.gui.extensions.QuPathExtension
- Create a companion text file
META-INF/services/qupath.lib.gui.extensions.QuPathExtension
with a single line of contents that gives the full classname of the class created in Step 1. - Package both the class at the text file into the same Jar.
We will not describe steps 2 and 3 in detail here. If they seem odd, then it may help to read around Services
and Service Providers
in Java here, since this is what QuPath extensions are based on.
However, the easiest way to get started is to copy and modify an existing extension that is available. The primary task is then to implement the QuPathExtension
interface. Fortunately, this is rather straightforward:
package qupath.lib.gui.extensions;
import qupath.lib.gui.QuPathGUI;
/**
* Simple interface for QuPath extensions.
*
* This allows dynamic discovery of new extensions.
*
* @author Pete Bankhead
*
*/
public interface QuPathExtension {
/**
* Install the extension for a QuPathGUI instance.
*
* This generally involves adding new commands to appropriate menus.
*
* (Where multiple extensions are present, the order in which they will be installed is undefined.)
*
* @param qupath
*/
public void installExtension(QuPathGUI qupath);
/**
* A readable name for the extension.
*
* @return
*/
public String getName();
/**
* A short description of the extension for displaying in the main GUI.
*
* This could also contain licensing information.
*
* @return
*/
public String getDescription();
}
The name and description can be almost anything - they are simply used for display. The installExtension(QuPathGUI qupath)
method is the important one, since this is what allows the extension to make changes - such as adding new commands. This method is called once by QuPath.
An example of how simple an implementation of this interface may be is shown below. It shows how the RichScriptEditorExtension
replaces QuPath's default (bland, black-and-white) script editor with something more colorful:
package qupath.lib.scripting;
import qupath.lib.gui.QuPathGUI;
import qupath.lib.gui.extensions.QuPathExtension;
/**
* QuPath extension to add a more attractive script editor with syntax highlighting,
* making use of RichTextFX, Copyright (c) 2013-2014, Tomas Mikula (BSD 2-clause license).
*
* @author Pete Bankhead
*
*/
public class RichScriptEditorExtension implements QuPathExtension {
@Override
public void installExtension(QuPathGUI qupath) {
qupath.setScriptEditor(new RichScriptEditor(qupath));
}
@Override
public String getName() {
return "Rich script editor extension";
}
@Override
public String getDescription() {
return "Adds a more attractive script editor with syntax highlighting, making use of RichTextFX - https://github.com/TomasMikula/RichTextFX";
}
}
Admittedly, the extension does require a separate class to actually implement RichScriptEditor
, and a Maven project to manage the dependency on RichTextFX
. Nevertheless, once these have been written then getting them into QuPath is quite straightforward: simply put both the Jar containing the extension and any dependencies (also Jars) into QuPath's extensions folder, and the next time QuPath is started they should be automatically discovered and installed.
The above extension replaces QuPath's default script editor using a specific method for this purpose. Supposing that this wasn't the desired effect, and rather the new script editor should have its own menu item (so that either editor could be opened), then the installExtension
method might be modified as follows.
@Override
public void installExtension(QuPathGUI qupath) {
// Get a reference to a menu, creating it if necessary
Menu menu = qupath.getMenu("Automate>Rich script editor", true);
// Create a new MenuItem, which shows a new script when selected
MenuItem item = new MenuItem("Show Rich script editor");
item.setOnAction(e -> {
new RichScriptEditor(qupath).showNewScript();
});
// Add to the menu
menu.getItems().add(item);
}
This alternative would add a new command to QuPath's menus that launches the new script editor. It takes advantage of a getMenu(String name)
helper method to request a particular menu (or submenu, through the use of >
), so that it may be added wherever is appropriate.
The extension API is open to change and improvement to meet new needs, making 'best practice' hard to define at this time. However, one thing that is good to keep in mind is that it helps to have version information in the Jar Manifest file.
If using Maven for dependency management, this can be achieved by including the following in the POM file for the extension:
<!-- Store the version information in the Manifest -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
In this case, QuPath is able to show the version number defined in the POM under the Help → Installed extensions menu.
These docs are for QuPath ≤ v0.1.2.
For more up-to-date information, see https://qupath.readthedocs.io
- Video tutorials
- First steps
- Viewing images
- Drawing regions
- Counting cells
- Projects
- Multiple images
- Preferences
- Getting help
- Object-oriented analysis
- Types of object
- Object measurements
- Object classifications
- Object hierarchies
- Working with objects
- Workflows
- From workflows to scripts
- Writing custom scripts
- Advanced scripting with IntelliJ
- Scripting examples