Adding new tabs to the QuPath analysis panel from Groovy

Hello,

since my post about adding toolbar buttons from Groovy, I’ve been thinking about ways to add more complex / experimental controls to QuPath. A good place might be in the form of additional tabs to the analysis panel, like so:

The code to do this is not complex, but...
def customId = "custom_tab"

// Remove all the additions made to the analysis panel based on the id above
def RemoveTab(panel, id) {
    while(1) {
        hasElements = false
        for (var tabItem : panel.getTabs()) {
            if (tabItem.getId() == id) {
                panel.getTabs().remove(tabItem)
                hasElements = true
                break
            }
        }
        if (!hasElements) break
    }
}

Platform.runLater {
    gui = QuPathGUI.getInstance()
    analysisPanel = gui.getAnalysisPanel()
    RemoveTab(analysisPanel,customId)
    BorderPane pane = new BorderPane()

    Tab newTab = new Tab("CustomTab", pane)
    newTab.setId(customId)
    newTab.setTooltip(new Tooltip("This tab is Groovy :-)"))
    
    analysisPanel.getTabs().add(newTab)
}

import javafx.application.Platform
import javafx.stage.Stage
import javafx.scene.Scene
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.geometry.Orientation
import javafx.scene.control.*
import javafx.scene.layout.*
import javafx.scene.input.MouseEvent
import javafx.beans.value.ChangeListener
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import qupath.lib.gui.QuPathGUI

It only works because I added the following public function to QuPathGUI.java:

	/**
	 * Get the analysis panel.
	 * @return
	 */
	public TabPane getAnalysisPanel() {
	    return analysisPanel;
	}

For a first test, I wasn’t sure whether I needed direct access to analysisPanel or not, but maybe returning analysisPanel.getTabs() in the same way getToolbar() returns toolbar.getToolbar() makes better sense (and name the function getAnalysisTabs() ?).

Is this something you might consider adding to a next revision?

Thank you kindly :slight_smile:

Actually, Groovy is so lax about public/private things that gui.analysisPanel works just fine – no changes to the QuPath code needed :slight_smile:

But yes, we’ll definitely think about giving a public method to access the TabPane in the future as well.

2 Likes

Oh wow, I did not know that! This is both awesome and frightening :wink:

Thanks to your suggestion, here’s an updated version that works out of the box:

def customId = "custom_tab"

// Remove all the additions made to the toolbar based on the id above
def RemoveTab(panelTabs, id) {
    while(1) {
        hasElements = false
        for (var tabItem : panelTabs) {
            if (tabItem.getId() == id) {
                panelTabs.remove(tabItem)
                hasElements = true
                break
            }
        }
        if (!hasElements) break
    }
}

Platform.runLater {
    gui = QuPathGUI.getInstance()
    panelTabs = gui.analysisPanel.getTabs()
    RemoveTab(panelTabs,customId)
    BorderPane pane = new BorderPane()

    Tab newTab = new Tab("CustomTab", pane)
    newTab.setId(customId)
    newTab.setTooltip(new Tooltip("This tab is Groovy :-)"))
    panelTabs.add(newTab)
}

import javafx.application.Platform
import javafx.stage.Stage
import javafx.scene.Scene
import javafx.geometry.Insets
import javafx.geometry.Pos
import javafx.geometry.Orientation
import javafx.scene.control.*
import javafx.scene.layout.*
import javafx.scene.input.MouseEvent
import javafx.beans.value.ChangeListener
import javafx.scene.image.Image
import javafx.scene.image.ImageView
import qupath.lib.gui.QuPathGUI
1 Like

It is! I’ve used that more times than I should…

A discussion for another thread, but I was blown away by your video on QuPath + Omero.

That’s basically what got me thinking about writing an “OMERO tab” to select images and datasets from. Maybe I could make use of the REST API (the JSON structures maybe like output by the IDR server) to populate some sort of a tree view / selection tool in the tab.

Anyway, super preliminary idea and no code to show yet! :slight_smile:

Great! You may be more blown away by what @melvingelbard has been doing more recently with the OMERO integration :slight_smile:

2 Likes