Capturing Mouse Input

Hello,

I would like to ask the user to input coordinates by clicking on a point in the volume. How do I achieve this?

I guess I would prompt them using a QMessageBox, but I would also like to change the pointer to something like this

and actually await the input…

Thanks

Hi Mohamed,

you may try to do a segment editor effect. For example, you can take a look at the user-interactions available in the paint effect (works both in 2d and 3d: takes the input coordinates for left-click events) and create your own:

The editor has an effects factory, so you can register your new editor effect very simply, something like this:

Cheers,

Davide.

1 Like

You can use the Markups module to go into fiducial placement mode, see
the “Adding
Fiducials via Mouse Clicks” section here:
https://www.slicer.org/wiki/Documentation/Nightly/Modules/Markups

Nicole

1 Like

Modules in VMTK extension uses fiducials as seeds. You can check out how add a widget to your module that can create/select fiducials: https://github.com/vmtk/SlicerExtension-VMTK/blob/master/CenterlineComputation/CenterlineComputation.py#L74-L86

You can tune it to create/select fiducial list by default and only show the place widget with a single button to place widget.

See also these examples:

1 Like

When I execute self.promptSeedSelect("background")
It is returning [0,0,0]. Is there any way I can force the program to wait for a mouse click when the user clicks ‘Ok’?

  def promptSeedSelect(self, seed):
    c = ctk.ctkMessageBox()
    c.setIcon(qt.QMessageBox.Information)
    c.setText("Click on a point in the %s to select the seed" % seed)
    c.setStandardButtons(qt.QMessageBox.Ok)
    c.setDefaultButton(qt.QMessageBox.Ok)
    answer = c.exec_()
    if answer == qt.QMessageBox.Cancel:
      logging.info("Terminating...")
      self.logic = None
      return

    logging.info("Coords are: " + self.drawFiducial(seed))

  def drawFiducial(self, seed):
    ras = [0.0,0.0,0.0]

    fidNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLMarkupsFiducialNode', seed)
    selectionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSelectionNodeSingleton")
    selectionNode.SetReferenceActivePlaceNodeID(fidNode.GetID())
    interactionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLInteractionNodeSingleton")
    # For multiple clicks, change this to 1
    placeModePersistence = 0
    interactionNode.SetPlaceModePersistence(placeModePersistence)
    interactionNode.SetCurrentInteractionMode(1)

    fidNode.GetNthFiducialPosition(0, ras)

    return ras

You need to add an observer on the fiducial list node for the
slicer.vtkMRMLMarkupsNode.MarkupAddedEvent
and then you can get the last fiducial position since it’s then been added.

Nicole

1 Like

Thank you. When I did that, the code runs fine but then I couldn’t get it to capture the input a second time if the user chooses to. Here is my full code:

To reproduce my problem, select this extension from Slicer’s Extension Wizard, then add a breakpoint to line 265 and set a watch with the following:
slicer.mrmlScene.GetNodeByID(“vtkMRMLInteractionNodeSingleton”).GetCurrentInteractionMode()

You’ll see that it shows 1 in the debugger, which we want, but then when it exits the call stack, it spontaneously switches to 2, which does not allow placement of a fiducial.

To facilitate placement of multiple markups, use qSlicerMarkupsPlaceWidget.setPlaceMultipleMarkups(ForcePlaceMultipleMarkups).

As I see, you have commented out the markup place widget, while you shouldn’t have, because that widget is exactly what you need (it makes sure that the correct markup list is selected, placement mode is active, and single/multiple markup placement option is selected). Just add this widget to the GUI and modify the place multiple markups mode:

self.seedFiducialsNodeSelector.markupsPlaceWidget().placeMultipleMarkups = slicer.qSlicerMarkupsPlaceWidget.ForcePlaceMultipleMarkups

Thank you for all your help so far. The reason I commented out the widget is because it would require more manual work from the user. I just want the user to be able to choose whether to add more markups or to stop adding more, using this dialog
image

When the user clicks “Add More”, it should create a new fiducial and set an observer to it and show this dialog when the user places a markup, and so on, until the user clicks “Save All”, then it would move to the next step. However, the problem I mentioned above happens when the user clicks “Add More”, and I don’t know why…

Instead of the “Add more” button, use the place widget, configured to show only a single place button, with single markup place mode. It works reliably, used in many modules.

w = slicer.qSlicerMarkupsPlaceWidget()
w.buttonsVisible = False
w.placeButton().show()
w.setMRMLScene(slicer.mrmlScene)
w.setCurrentNode(getNode('F'))
w.placeMultipleMarkups = slicer.qSlicerMarkupsPlaceWidget.ForcePlaceSingleMarkup
w.show()

image

1 Like