As I can see there is qMRMLThreeDViewControllerWidget.ui wich is popup widget when one clicks on pin button of a three D view.
I want to add there some buttons.
To do that I need to get instance of it qMRMLThreeDViewControllerWidget.
There is a method LayoutManager->threeDWidget(0)->threeDController() wich returns qMRMLThreeDViewControllerWidget* but this returns the whole 3D widget instead. There are also some other methods (displayed on the picture) but there is no one that would return me ctkPopupWidget (it is initialized in qMRMLViewControllerBar.cxx). Pin button is connected to the slot wich arises popup widget but I can’t see a way to get instance of it…
There are convenience methods for getting higher-level widgets and after that you can use standard Qt introspection to access lower-level widgets. For example, you can add a button to the view controller widget like this:
By the way I just tested and to do almost the same in C++ I needed call findChild template with ctkPopupWidget* type:
ctkPopupWidget* popupWidget = controller->
findChild<ctkPopupWidget*>("qMRMLThreeDViewControllerWidget");
QGridLayout* gridLayout = qobject_cast<QGridLayout*>(popupWidget->layout()); // don't know why but this returns me NULL
QToolButton* cubeAxesToolBtn = new QToolButton(popupWidget);
// gridLayout->addWidget(cubeAxesToolBtn, 0, 4); // as I can't yet cast layout to gridLayout then I comment this
popupWidget->layout()->addWidget(cubeAxesToolBtn);
How do you think if I create PR where I add a method getPopupWidget() to qMRMLThreeDViewControllerWidget that would return popupWidget?
Because it is very intuitive to have a guess that there should be some method that returns that popup widget. And if there is no such method then it is difficult to understand who is the parent and the type of that widget… As for me without you I would not solve that simple task
The same I could do with qMRMLSliceControllerWidget.
We try not to expose too much of the low-level Slicer API because that would limits us in how we can add features without breaking backward compatibility. When you don’t find an accessor for some low-level features then it usually means “Do Not Open - No User Serviceable Parts Inside” (we don’t make a commitment to maintain the API, we don’t want to troubleshoot problems due to developers changing those parts, etc.). It happens sometimes that some APIs just has not yet been considered to be exposed (there was no need for it).
The popup widget is fairly high-level and stable (not expected to change a lot in the near future), so it might be OK to add an accessor for it, but I would rather do it if at the same time you introduce a mechanism that allows customization of the button list more cleanly. It does not make sense to remove low-level Qt method calls to get the widget, if you still need to execute a number of similarly low-level calls to make any changes in the buttons.
For example in my case I need to move some tollbuttons inside grid layout. I’m going to add a zoomer that zooms selected region rectangle (in VTK examples there is such tool). I would like to settle all zoom buttons near each other. To do that I’m going to use QLayout::replaceWidget() in pair with findChild() (I have not tried yet I think it should work) to find a specific tool button. I don’t know what mechanism could I introduce… Maybe you have some ideas/examples?
Segment Editor effects: you can register new effects, specify order of effects, and choose to show only those effects that you included in the ordered list
subject hierarchy view context menu items: you can register new actions, specify their “weight” that determines their position and grouping in the list, and you can provide a whitelist of actions using allowedViewContextMenuActionNames
You would need some kind of factory mechanism that would allow creating new actions in each 3D view automatically.
If you find that the menu bar, status bar, etc. take up significant amount of space then it suggests that your application font is too large. You can set text scale in your operating system, or in Slicer application settings, or specify scaling by setting QT_SCALE_FACTOR environment variable (e.g., set QT_SCALE_FACTOR=0.75).
If you still want to hide all user interface elements then you are probably better off specifying a keyboard shortcut for it.
@keri
Thank you for your reply! However, I wonder how to remove the button “under” the pinButton, not the pintButton itself. I mean, i want some of the button “under” the pinButton to be removed and some added.
I think you know that Slicer uses Qt for displaying GUI.
All you can see are Qt widgets (widget is some base class for any GUI element in Qt)
Qt GUI uses parent-child hierarchy (some kind of a tree structure I think).
So if you have instance of a parent object, there a good chances to find child needed.
To find child needed you need to know some information about the child widget (probably button in your case) that you want to get.
For example such information may be objectName, and/or the type of a widget (QPushButton, QToolButton etc, examples below).
Then you can use these information for example using the syntax slicer.util.findChild(parent ,“objectName”)
Or sliceController.findChild("QPushButton", "objectName") (slicerController is supposed the parent in that case).
Or probably sliceController.pinButton().findChild(...)
So the problem is how to get the information about the child?
For example I usually look for a tooltip (by pointing the mouse cursor) of a widget that is located “close” to the widget I want to get. Or if I already know that the widget is a part of some module then I go to source code of Slicer and in VSCode textual editor I paste the keyword (the tooltip for example).
Usually many Slicer’s widgets are “written” in QtDesigner thus you may want to find the .ui file containing some graphically displayed widgets. There you can find most of the information needed.
If you can’t find information about the child then you try to iterate the children and the if it fits you.
Or you may ask on the forum what exactly the widget you want to find, probably for somebody it is not a problem to remember the object name of this widget.
And one note: in Slicer’s python interpreter you can press TAB button of the keyboard to get the hints about the methods of an object.
For example: sliceController.<press TAB> a popup window will be shown
or dir(sliceController) will print the info
But the most powerful method is to use SlicerJupyter
There you can also use TAB or SHIFT-TAB to get hints. It is a good place to work/make mistakes/learn Slicer from python side