# Understanding UI Editing and Python File Generation in 3DSlicer with Qt Designer

**URL:** https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369
**Category:** Development
**Created:** [November 25, 2024, 4:45pm UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369 "2024-11-25T16:45:32Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)
#### Post date: [November 25, 2024, 4:45pm UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/1 "2024-11-25T16:45:32Z")

</div>

Hello Dear Developers and Users,

In the implementation of the module, I am using the **Extension Wizard** module. This module utilizes a fixed template, the result of which ultimately creates a **.ui** file and its corresponding Python file. For example, let’s assume that the name of this module is _developModuleTry01_. After switching to the _developModuleTry01_ module, I can run the **Qt Designer** within 3DSlicer and add or remove the module’s widgets. After saving and exiting **Qt Designer** , I click on **Reload and Test** to apply the changes. However, I noticed that the Python file does not change when I edit the UI file. I also checked other options of the _developModuleTry01_ module, including **Reload** and **Restart Slicer** , but I observed that the Python file still doesn’t change when I edit the module’s UI.

Is it a correct and reasonable expectation that the Python file should also change when I edit the UI through **Qt Designer**?

I know that, in general, to generate Python code from a UI file created with **Qt Designer** , tools like or **pyuic** or **pyuic5** should be used. Similarly, in 3DSlicer, a tool similar to **pyuic5** should be used, and it is expected that when using **Edit UI** and clicking on **Reload and Test** , two things should happen:  
one, the graphical environment of the module is reloaded, and  
two, a tool like **pyuic5** is executed to regenerate the Python file.

Is my assumption incorrect?  
Please guide me.  
Best regards.  
Shahrokh

---

<div class="post-metadata">

### Author: ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)
#### Post date: [November 25, 2024, 7:44pm UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/2 "2024-11-25T19:44:05Z")

</div>

> [@shahrokh](#):
>
> I can run the **Qt Designer** within 3DSlicer and add or remove the module’s widgets. After saving and exiting **Qt Designer** , I click on **Reload and Test** to apply the changes. However, I noticed that the Python file does not change when I edit the UI file.

This is expected. The UI file is an xml file in the Resources/UI subdirectory that is used to build the widgets for the module GUI. The default python module script from the template reads this file with a line like `uiWidget = slicer.util.loadUI(self.resourcePath("UI<module>.ui"))` so the python code doesn’t need to change with you edit the ui file.

---

<div class="post-metadata">

### Author: ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)
#### Post date: [November 26, 2024, 5:15am UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/3 "2024-11-26T05:15:01Z")

</div>

Thank you very much for your response, but perhaps I should explain the reason for asking this question so that, if possible, you may guide me further.

Perhaps you have already read the question I raised in my previous message with the title of [Implementing Widgets for Selecting Nodes of Type Segment and Beam](https://discourse.slicer.org/t/implementing-widgets-for-selecting-nodes-of-type-segment-and-beam/40359). In general, I want to familiarize myself with the process of developing modules in 3DSlicer. Therefore, I want to learn how I can develop the functionality of widgets so that I can select specific nodes from the Data module and process them. For example, with one widget, I should be able to select only nodes of type **Segment** , with another widget, only nodes of type **Model** , and with yet another widget, only nodes of type **Beam**.

Based on this, the roadmap I set for myself was to first create a UI that contains a widget of type **qMRMLSegmentSelectorWidget** to select only nodes of type **Segment**. The reason I chose this node is that I found out this widget is part of the **Slicer [MRML Widgets]** in Widget Box of Qt Designer, and it seems to have been specifically added to Qt Designer by the 3D Slicer development team for module implementation. (At this point, I also had a problem, as I couldn’t find other widgets in the list that, based on their names, I could guess might be useful for selecting nodes of specific types.)

By selecting this particular widget, I expected that the related Python file would be much shorter so I could analyze and understand its components, and ultimately develop its function so that it would select only nodes of type **Segment** from the Data module. As I mentioned in my message, the Python file that was generated was default and contains 403 lines.

Best regards.  
Shahrokh

---

<div class="post-metadata">

### Author: ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)
#### Post date: [November 26, 2024, 8:01pm UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/4 "2024-11-26T20:01:29Z")

</div>

It sounds like what you are looking for is a [qMRMLNodeComboBox](https://apidocs.slicer.org/master/classqMRMLNodeComboBox.html). You can use the `nodeTypes` property and other api options to control what gets displayed. These are used all over Slicer, so looking at the code will give you ideas how to use it.

---

<div class="post-metadata">

### Author: ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)
#### Post date: [November 27, 2024, 8:23am UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/5 "2024-11-27T08:23:32Z")

</div>

Thank you very much for the guidance you provided. I will definitely implement the point you mentioned in my module.

The plans I have in mind are to implement modules with names such as VolumeSelector, ModelSelector, BeamSelector, etc., separately, in order to expand my experience in module development.

However, if you pay attention to the following figure, you will notice that the parent class used is of type **qMRMLWidget**. Interestingly, the **qMRMLSegmentSelectorWidget** widget does not have the **nodeType** property.

 ![1](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/9/79341869bfc1442f52602dbb904bca27fa07b245.png)

But as mentioned you, if a widget of type **qMRMLNodeComboBox** is selected, it does have the **nodeType** property, and I think I should set it to **vtkMRMLScalarVolumeNode** or **vtkMRMLSegmentationNode** in python code.

 ![2](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/4/3/43251733a8241963b01c9fda03cdd9b40ed582b3.png)

Best regards.  
Shahrokh

---

<div class="post-metadata">

### Author: ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)
#### Post date: [November 30, 2024, 7:44am UTC](https://discourse.slicer.org/t/understanding-ui-editing-and-python-file-generation-in-3dslicer-with-qt-designer/40369/6 "2024-11-30T07:44:06Z")

</div>

Thank you very much for the helpful guidance regarding the property `nodeTypes`. Based on your response and the answer that Csaba Pinter provided to the question raised by Thomas Dutrey titled [Input segments in new module](https://discourse.slicer.org/t/input-segments-in-new-module/5064), I was able to implement two separate modules named **VolumeSelector** , **SegmentSelector** and **RTBeamSelector**.

As mentioned in the response, the key lines in the corresponding Python code files, **VolumeSelector.py** , **SegmentSelector.py** and **RTBeamSelector.py** , are the following lines, which determine the type of node in the Selector:

In the **VolumeSelector.py** file:

```auto
    # input volume selector
    #
    self.inputSelector = slicer.qMRMLNodeComboBox()
    self.inputSelector.nodeTypes = ( ("vtkMRMLScalarVolumeNode"), "" )
    #self.inputSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", 0 )
    self.inputSelector.selectNodeUponCreation = True
    self.inputSelector.addEnabled = False
    self.inputSelector.removeEnabled = False
    self.inputSelector.noneEnabled = False
    self.inputSelector.showHidden = False
    self.inputSelector.showChildNodeTypes = False
    self.inputSelector.setMRMLScene( slicer.mrmlScene )
    self.inputSelector.setToolTip( "Pick the input to the algorithm." )
    parametersFormLayout.addRow("Input Volume: ", self.inputSelector)

```

In the **SegmentSelector.py** file:

```auto
    # input segment selector
    #
    self.inputSelector = slicer.qMRMLNodeComboBox()
    self.inputSelector.nodeTypes = ( ("vtkMRMLSegmentationNode"), "" )
    #self.inputSelector.addAttribute( "vtkMRMLSegmentationNode", "Segment", 0 )
    self.inputSelector.selectNodeUponCreation = True
    self.inputSelector.addEnabled = False
    self.inputSelector.removeEnabled = False
    self.inputSelector.noneEnabled = False
    self.inputSelector.showHidden = False
    self.inputSelector.showChildNodeTypes = False
    self.inputSelector.setMRMLScene( slicer.mrmlScene )
    self.inputSelector.setToolTip( "Pick the input to the algorithm." )
    parametersFormLayout.addRow("Segment: ", self.inputSelector)

```

In the **RTBeamSelector.py** file:

```auto
    # input RT beam selector
    #
    self.inputSelector = slicer.qMRMLNodeComboBox()
    self.inputSelector.nodeTypes = ( ("vtkMRMLRTBeamNode"), "" )
    #self.inputSelector.addAttribute( "vtkMRMLRTBeamNode", "RTBeam", 0 )
    self.inputSelector.selectNodeUponCreation = True
    self.inputSelector.addEnabled = False
    self.inputSelector.removeEnabled = False
    self.inputSelector.noneEnabled = False
    self.inputSelector.showHidden = False
    self.inputSelector.showChildNodeTypes = False
    self.inputSelector.setMRMLScene( slicer.mrmlScene )
    self.inputSelector.setToolTip( "Pick the input to the algorithm." )
    parametersFormLayout.addRow("Beam: ", self.inputSelector)

```

Best regards.  
Shahrokh
