Include built-in widget into my own Python extension

Hi,

I want to develop a simple extension in Python. One step involves placing points on the 3D scene. I realized that the fiducial markup is perfect for my use case, so I want to add that icon, along with the logic it implements, into my own frame. The idea is to simply add the pushbutton widget
fiducial
and also the list that keeps track of the points the user creates:
list
but not the other markup tools (line markup, angle markup, etc.).
Where can I find these two widgets? I looked for them in the API docs and in the source code folder, but could not figure out how to import them as Python modules, so that I can use them from within Python.

Thanks,
Zoltan

Take a look at Slicer: qSlicerMarkupsPlaceWidget Class Reference. This widget can handle creating and selecting a fiducial node and toggling placement mode for points. One common stumbling point is that you need to set the mrml scene before the widget will be functional. This can be done in Qt Designer when you are setting up the UI by connecting the module widget’s mrmlSceneChanged(vtkMRMLScene*) signal to the MRML widget’s setMRMLScene(vtkMRMLScene*) slot. Or it could be done in your module’s setup function.

That’s very useful to me. I’ll try on my projects.

Thank you. Although I connected the proper signal to the proper slot, the widget is not activated. This is strange because the same workflow works for the qSlicerSimpleMarkupsWidget widget.

More importantly, can I modify an already existing widget (e.g. by removing certain parts it) without recompilation? I am afraid I can’t because the Markups module is implemented in C++.

Markups place widgets also require an active current markups node to be activated (sorry I omitted that in the first answer, I forgot!). Here is an example of setting that:

myFiducialNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLMarkupsFiducialNode', 'F')
w = slicer.qSlicerMarkupsPlaceWidget()
w.setMRMLScene(slicer.mrmlScene)
w.show() # not active yet
w.setCurrentNode(myFiducialNode) # now it is active

You can control whether parts of the widget are shown or not from Python without recompilation. All qt widgets have hide() and show() functions, so if you want to hide a part of the custom widget you just need to find that part and invoke its hide() method. For example, if you wanted to hide the color picker button, the following would work:

# w is the markups place widget we set up above
childrenList = w.children()
colorButton = childrenList[8] 
colorButton.hide()

I found that the color button was the child with index 8 by just inspecting the list of the widget’s children (I don’t know a more efficient way to do that and I’m not that familiar with Qt, but it is not very much work to look through the full list).

2 Likes

Getting a button by index is very fragile. It is safer to retrieve a button object by name, for example:

colorButton = slicer.util.findChild(w, 'ColorButton')

But the safest is to use the public API of the widget. For example, you can make the widget only show a place button like this:

w.buttonsVisible = False
w.placeButton().show()

Not all the buttons are exposed on the public API. We could change that, but was not needed until now.

2 Likes