Popup menu in displayablemanager

Hi all,

I’m trying to develop a Slicer module in which right clicking within a 2d slice view will generate a popup menu.

I’m implementing this functionality in DisplayableManager. I haven’t found a VTK object that implements a popup menu. Instead, I’ve created a DisplayableManagerMenu QOBJECT that has some slots that can be called from a QMenu object.

To get this to compile required changing the CMakeLists.txt file to build the MRMLDM library using SlicerMacroBuildModuleWidgets instead of SlicerMacroBuildModuleLogic, so that I can specifiy the DisplayableManagerMenu as an MOC source.

This actually worked, UNTIL I rebuilt the extension from scratch (ie, removed the entirety of the build directory and recompiled). Then I started getting the following error:

“vtkMRMLSliceViewDisplayableManagerFactory (0x55e643f3d890): RegisterDisplayableManager - Test1DisplayableManager is not a displayable manager. Failed to register”

Interestingly, it works just fine when I initially switch from SlicerMacroBuildModuleLogic to SlicerMacroBuildModuleWidgets if I don’t rebuild from scratch in between. Looking into how these two SlicerMacroBuildModule* functions work, they eventually call SlicerMacroBuildVTKLibrary and SlicerMacroBuildQtLibrary respectively. I get the sense that what I’m trying to do runs contrary to some deep limitation or assumption, since what I seem to need would be a function called “SlicerMacroBuildVTKandQtLibrary”.

I have also tried adding the relevant QT5_WRAP_CPP into a CMakeLists.txt that uses SlicerMacroBuildModuleLogic, but run into problems when Python tries to wrap the moc_DisplayableManagerMenu.h file since that doesn’t exist. Disabling python wrapping generates the same error as above.

Does anyone have any suggestions about:

  1. What SlicerMacroBuildModuleLogic is doing that gets the DisplayableManager registered correctly that isn’t done by SlicerMacroBuildModuleWidgets?

  2. Whether there is a VTK-based alternative to QMenu for generating popup menus?

  3. Any example extensions that implement something similar to this?

Thanks,
-Paul

Displayable managers are VTK objects, they do not depend on Qt, so you won’t be able to use any Qt classes there. However, you can invoke VTK events and you can add observers to VTK events from Qt classes. You should not modify any existing displayable managers, just add your own.

If you want to interact with specific nodes that are displayed in a viewer, then you can add observers to events of that node. For example, you can use the code below to show a menu when user left-clicks on a markup:

menu = qt.QMenu()
a1 = qt.QAction("test", slicer.util.mainWindow())
#a1.connect('triggered()', self.select)
menu.addAction(a1)
a2 = qt.QAction("action", slicer.util.mainWindow())
#a2.connect('triggered()', self.select)
menu.addAction(a2)
a3 = qt.QAction("here", slicer.util.mainWindow())
#a3.connect('triggered()', self.select)
menu.addAction(a3)

@vtk.calldata_type(vtk.VTK_INT)
def markupCallback3(caller, eventId, callData):
  menu.move(qt.QCursor.pos())
  menu.show()

markupsNode = getNode('F')
observerTag = markupsNode.AddObserver(slicer.vtkMRMLMarkupsNode.PointClickedEvent, markupCallback3)

Note: There is a small bug that makes a menu appear after clicking on the slice view after clicking a markup (https://github.com/Slicer/VTK/pull/13). A fix for it should be integrated soon.

Thanks Andras, that worked great.

I’m developing in C++ so what I did was:

  • invoke an event on the MRMLNode from within the VTKWidget
  • set up an observer of the MRMLNode at the Module level
  • create QMenu subclasses at the Widget level

Thanks again,
-Paul

1 Like

@lassoan Thanks for the fix, it has been merged into upstream VTK.

Also starting with r26697, Slicer includes the fix.

1 Like