Creating a 3D Slicer extension with minimal programming skills

Your advice worked on my selector problem, thanks ! I managed to do the first tutorial fairly entirely (not the sphere thing), except that I am not getting a functionnal auto update. I have been trying several things and I’m not getting what’s the problem. I would like to manage it since auto update is an interesting feature !

My function is as follows :
image
I don’t really get how the part I marked really works, like I tried to see self.ui.inputSelector.currentNode and it’s not a boolean so I don’t get how it can work as an “if” condition. Tryed commenting it, didn’t change anything, so I’m a bit blocked

First, you want to have the parentheses on the end of the self.ui.inputSelector.currentNode() in the if line as well. In Python, if you use the name of a function with parentheses, then you call that function, but if you use the name without parentheses, you just get a reference to the function (and the function is not actually called). Second, in an if statement, python treats almost anything as True, unless it is empty, None, zero, or explicitlly False (here’s a link that gives you the real details). The currentNode() function of node selectors returns the selected node (if one is selected) or None if there is no selected node. Since None counts as False and a node would count as True, it works to include this in the if.

The first line after the if stores the currently selected node in self.observedMarkupNode, so that it can be accessed later in other parts of the code (like in the previous if where the observer we’re about to create is removed). The next line creates an “observer” such that whenever the observed markups node is modified (by the user or by other code), another function (self.onMarkupsUpdated) is called. Since onMarkupsUpdated() just calls onApplyButton(), the ultimate effect is that anytime the user makes changes to the markups, it is like they followed that by clicking the Apply button as well.

Hello Mike, thank you for the answer, indeed the lack of parenthesis was weird. Fixed now. But it still isn’t working : when I move or add a markup, nothing happens, the displayed Center Of Mass doesn’t change. Can it be that since my “CenterOfMassValueLabel” is above the ApplyButton on the GUI, it doesn’t work because of that?
Also in QtDesigner I linked the CheckBox with the scene through a “toggle”, should I change for click?

@mikebind you said that a lot of what you do on Slicer is rearranging the GUI to create new workflows so I have a few questions :

I want to create some kind of workflow interface as follows :

  1. File loading manually (drag and drop would be cool)
  2. Selecting a segmentation scenario according to the type of image and anatomical parts to be treated
  3. Segmentation using a limited set of methods (I want to display only the needed methods for this particular scenario, not everything that is available)
  4. Exportation of the segments as STL files

So my questions are :

  1. I would like to not overcrowd the interface, so I am thinking of doing something like several interfaces that are displayed in the order of the phases and linked with a “previous/next” button, is it feasible? Do I need to have several QtDesigner files with the specific interface on each or is it one file with different pages?
  2. For the segmentation part especially, is there a way to fully reuse what is done in the segment editor but with just a limitation of the available effects? Or do I have to recreate the whole thing manually?
  3. I’ve seen in QtDesigner that there is a SegmentEditorWidget that basically displays the whole thing at once but I have not been able yet to understand how the connexion is done. It seems a bit different from simple buttons. And can I edit this widget? Because I haven’t found a way to access the internal features of the Widget…

Sorry for the amount of questions, I really appreciate any help !

I haven’t been through that tutorial or ever done auto-updating in response to markups changes, and the full code isn’t shown, so I’m not sure I can help debug that much further. You might take a look at this code from the script repository and see if that works for you and if you can adapt it to your purposes.

I don’t know how to do this, but I believe it is possible. Loading via the Add Data method has never seemed cumbersome enough to me to pursue it.

Automatically? Then you need to come up with the decision algorithm and implement it. Manually? Then just pick your favorite UI method (buttons, radio buttons, etc.)

I have used segment editor effects from my modules, but have not tried to put a limited set of interactive effects to be available to the user. However, it looks like this discussion has exactly what you want.

This is straightforward. You can use slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsClosedSurfaceRepresentationToFiles() to export to STL or OBJ files.

The simple method used in many Slicer modules is to have sections with collapsible buttons. This allows areas which are not in current use to be collapsed and take up less room, allowing more screen space for the active area. You can set up your code to automatically collapse and expand sections at the proper times. For example, if I have a section in a collapsible button which is self.ui.CTRegistrationAreaCB I can collapse it with self.ui.CTRegistrationAreaCB.collapsed = True. For another approach, I believe Qt also allows tabbed layouts, but I’ve never tried that or looked into it so I can’t really help with that. Another possible approach would be to have multiple modules that you switch between (see this discussion). Also, I would highly recommend taking a look at Slicelets.

This discussion looks like it answers your question directly.

If you want to see an example of a working module which uses specific segment editor effects (but not the same way as they appear in the Segment Editor module) you could take a look at Heartbeat4D/PropagateSegToOtherPhases.py at main · mikebind/Heartbeat4D · GitHub The code there is old, written before Qt Designer became the default way of creating the UI, but it still works fine. It makes use of thresholding, grow from seeds, erode, close holes, masking, creating empty segments, and copying from one segmentation to another.

I’ve created a small example project of a slicelet (3D Slicer running with a simplified GUI) that you might find useful. It is only for loading an image, segmenting it, and saving the result. See more details here: Documentation/Nightly/Developers/Slicelets - Slicer Wiki

You can easily customize everything and can switch between simplified/full Slicer GUI by adding a keyboard shortcut.

Wow that’s a lot of information from everyone, thanks !

This is quite exactly what I need indeed ! And I managed to adapt it to the Qt created Widget in Andras’ Slicelet example ! That is so great !

Yes I saw it before but I didn’t have the knowledge to understand it, now I do understand a lot more! This is very useful and very close to what I want to achieve, thank you!

I am testing it and there are a few things I notice :

  • My Slicer seems to run a bit slower when using the module, is it to be expected?
  • When I run it, and then I load or select a DICOM file in the Database, I don’t find a way to come back to the module page. Is there any way for me to add the icon of the module in the toolbars? So that the user can come back to it? I have tried to edit the code in the showSingleModule section (adding lines in keeptoolbars, commenting others underneath,…) but didn’t succeed.
  • the same way, I would like to show the ToolBars to control the views and the 3D (switching between views, navigating through the Slices, etc…) but commenting the slicer.util.setViewControllersVisible(not singleModule) line doesn’t seem to work

I think the Slicelet example is a great base for me to learn and do trials to achieve what I want ! thank you !

It is exactly the same Slicer (just some widgets are hidden), so it should not be any slower. If it is indeed slower then maybe there are some error/warning messages flooding the application log - you will see it when you check the logs.

All the other things that you describe should work, probably there are just some trivial errors. You can find them easily by attaching a Python debugger (PyCharm, Visual Studio Code, …) and step through your code line by line.

Okay I see, then it was also maybe my computer struggling a bit!

Since then, I managed to handle a lot better the interface changes and I’m starting to build a fairly satisfying interface for my use. But I still didn’t find the way to add an icon to get back to the module on the toolbar (to come back from the DICOM database), neither a way to display the navigating tool for the axis and 3D view displays (usually there is a slider with also a pin to show various options to switch between files, etc…) Is it possible to get these two things back on the interface by modifying the ToolBar section in the code?

image

Around there I guess? Did various tries without success…

You can add a button that switches the active module and/or changes the view layout (that shows slice and 3D views instead of the DICOM browser). You can find examples in the script repository.

You can show/hide view controllers by calling setViewControllersVisible.

Thanks ! It worked and I understand a lot better how the hide/show works.

I have searched the repository but I don’t think that what I want is adding a view layout. To be precise, what I am trying to do is displaying the “Favorite Modules” toolbar, and if possible edit it to display only my module or at least adding my module to the list through Python. I don’t know if I can do that. I have been trying to do the same hide/show manipulation as for the other toolbars but I don’t find the right way to call it and I wasn’t able to find any documentation on that.

I am getting really close to what I want so thanks for the patience ! Helps a lot

DICOM browser is shown in the view layout that’s why changing the view layout may be useful (you can be in the DICOM module and show the browser or show slice&3D viewers).

You may show the favorites toolbar (using standard Qt functions or convenience methods in slicer.util) but if you know exactly which modules you want to use then you can have a simpler, more compact GUI by placing a few buttons for switching between modules.

I am not sure I understand it correctly. What you mean by “view layout” is the toolbar just under File/Edit/View/Help, or is it the place where you can chose different layouts for the 2D and 3D views like “Four up” “Only 3D” etc?

Yes that’s exactly what I need ! But the thing is that I didn’t manage to add a button at the same level as the DICOM Database button so that it stays there when I switch.
image
I want to add a button there, can be through Python to avoid building a higher level window with Qt…

By view layout I mean four-up, red slice only, dicom browser, etc.

You don’t need the favorite toolbar, you can hide it and instead add buttons for switching between modules. If you prefer to have a tool bat then you can of course do that, too. Just make sure to set the Favorites toolbar visibility to True.

Yeah if I can avoid the favorite toolbar I will, the thing is I didn’t find the syntaxe to add a button at the level I showed (which doesn’t appear in Qt Designer) or the right way to right the line for the Favorites Toolbar set visible either. I am not familiar with the “old” way to create GUI elements but I feel it’s what I need for this particular button

You can only save space if you remove all the toolbars (then the toolbar area disappears). List of toolbars are specified here:

So, either add ModuleToolBar there or remove all the other toolbars and create a row of buttons using Qt designer.

Hello.

I´d recommend to go
→ Developer Tools → Extension Wizard

image

This helpful tool will put up a development system within slicer and comes with a working templet of a simple extension with it´s own GUI.

You can edit the python code in a text editor of your coice and play around with the GUI after editing it in the in the QT designer.

image

Reload the extension from within slider and directly test your changes, All basic and necessary functions for a slicer extension are included. But you will need to write some lines of code …

Best regards

Rudolf

1 Like

Okay ModuleToolBar is indeed what I tried to find, at least I got the Favorites so it’s quite good enough for now. The next step would be to set my Slicelet to be the only module in here I guess but that’s not urgent to do. Thanks a lot anyway !!

1 Like