How to handle selection changes from guiscripts?

Hi everybody,

I am currently writing a QuPath Groovy guiscript for version 0.2.3 where I would like to dynamically update a ComboBox based on the currently selected annotation, basically listen for the currently selected PathObject, get a measurement value and update the ComboBox’ selected entry.

I found that there is a addPathObjectSelectionListener() method but as I am really not very experienced with either Java, Groovy or JavaFX I would appreciate if somebody could point me at some ressources that might help me with the implementation of it. :slight_smile:

Thank you so much & best regards,

Simon

Hi @skalteis ,

As you can see here, the PathObjectSelectionListener is an interface for which you have to implement the selectedPathObjectChanged(..) method. this method is called any time there is a change in the PathObjectSelectionModel. Without a sample code, it is a bit complicated to give you the right way to do this (I can imagine more than one way to implement this).

If you want examples of classes that implement the interface, there are QuPathViewer, AnnotationPane, CountingPane and so on.

But it might be simpler to guide you if you post a sample of your script :slight_smile:

3 Likes

Hi @melvingelbard ,

so far the relevant part looks like this (imports omitted):

def ConfidenceLevels = [unspecified:0, low:1, medium:2, high:3];

def qupath = QuPathGUI.getInstance();

def comboBoxConfidenceLevel = new ComboBox();

ConfidenceLevels.each {
    entry -> comboBoxConfidenceLevel.getItems().add("$entry.key");
}

comboBoxConfidenceLevel.setOnAction((event) -> {
   def annotationSelected = qupath.viewer.getSelectedObject();
   def hierarchyCurrent = qupath.viewer.getHierarchy();
   annotationSelected.getMeasurementList().putMeasurement("ConfidenceLevel", ConfidenceLevels[comboBoxConfidenceLevel.getValue()]);
   hierarchyCurrent.fireHierarchyChangedEvent(annotationSelected);
});

qupath.getToolBar().getItems().add(new Separator(Orientation.VERTICAL));
qupath.getToolBar().getItems().add(comboBoxConfidenceLevel);

So on selecting an entry in the comboBox a measurement called “ConfidenceLevel” is added to the selected PathObject and the display in the list in the panel is updated.
What I’d like to add is the implementation for the other way around - update the combo box whenever the selected object changes so it displays the matching measurement and it’s consistent.

I had a look at the implementation of the annotation pane but I am a bit lost, do I have to create a new class derived of the ComboBox to use it? OOP and Java is definitely not my field… :slight_smile:

Thank you for your input!

Hello,

Here is a very minimal example that I just wrote quickly, but it should show you enough to inspire you with your code :slight_smile: Obviously there’s much more that you would have to guard against, but it should basically work (draw 2 annotations with different names on your image, run this sample, then check the text in the window changing depending on your selection):

import javafx.scene.control.Label
import javafx.stage.Stage
import javafx.scene.layout.HBox
import javafx.scene.Scene
import qupath.lib.objects.hierarchy.events.PathObjectSelectionListener

MyDialog md = new MyDialog(getQuPath())
md.run()

// Implement the interface, so that change in selection triggers method inside the class
class MyDialog implements PathObjectSelectionListener {

    QuPathGUI qupath
    Label label

    MyDialog(QuPathGUI qupath) {
        this.qupath = qupath
        this.label = new Label("Something")
    }

    void run() {
        qupath.getImageData().getHierarchy().getSelectionModel().addPathObjectSelectionListener(this)
        
        Platform.runLater(() -> {
            Stage dialog = new Stage()
            dialog.setScene(new Scene(new HBox(label)))
            dialog.showAndWait()
            dialog.setOnHiding() {
                qupath.getImageData().getHierarchy().getSelectionModel().removePathObjectSelectionListener(this)
            }
        })
    }

    @Override
    public void selectedPathObjectChanged(PathObject pathObjectSelected, PathObject previousObject, Collection<PathObject> allSelected) {
        // Here goes your selection change logic
        if (pathObjectSelected == null)
            label.setText("No selection")
        else
            label.setText("Name: " + pathObjectSelected.getName())
    }
}
3 Likes