# Changing the background of 3D view at startup

**URL:** <https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798>\
**Category:** Development\
**Created:** [July 29, 2019, 6:40pm UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798 "2019-07-29T18:40:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [July 29, 2019, 6:40pm UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/1 "2019-07-29T18:40:12Z")

</div>

Hi,

i have a class derived from qSlicerMainWindow (according to [https://github.com/KitwareMedical/SlicerCustomAppTemplate](https://github.com/KitwareMedical/SlicerCustomAppTemplate)).

In the method setupUi, after the line this-\>Superclass::setupUi(mainWindow); I am setting a custom layout. This works so far. The custom layout contains a new 3d view, which is generated correctly.  
After that, the scene contains three 3d views, which I find odd, I would have thought that the scene would only contain two of them after the change to my layout. One is called ‘View’, one is called ‘View1’, and one is called ‘View’.

When I then (still in setupUi) do the following:

```auto
  vtkMRMLViewLogic* ViewLogic = layoutManager->threeDWidget("My3dView")->viewLogic();
  vtkMRMLViewNode* ViewNode = layoutManager->threeDWidget("My3dView")->mrmlViewNode();
  ViewLogic->StartViewNodeInteraction(vtkMRMLViewNode::BackgroundColorFlag);
  int wasModifying = ViewNode->StartModify();
  ViewNode->SetBackgroundColor(0.0f, 0.0f, 0.0f);
  ViewNode->SetBackgroundColor2(0.0f, 0.0f, 0.0f);
  ViewNode->EndModify(wasModifying);
  ViewLogic->EndViewNodeInteraction();

```

the background color is unchanged when the main window appears.

Is there something wrong with my code or do I have to change the background color of the 3d views at a different place (i.e. somewhere later in program execution)?

Any advice would be appreciated.  
Robert

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 30, 2019, 2:54am UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/2 "2019-07-30T02:54:00Z")

</div>

Default view properties are read from application settings, written to default view and slice nodes in the scene, and then views are updated from the default nodes.

Here is an example of how [default nodes are set for slice views](https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Change_default_slice_view_orientation).

I would recommend to attach a debugger and step through the view initialization process to get familiar how it works.

---

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [July 30, 2019, 9:55am UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/3 "2019-07-30T09:55:15Z")

</div>

Thank you for the hint Andras, that helped me solve it.

I found out the following sequence of vtkMRMLViewNode creations:

1. Creation of qSlicerApplication - RegisterNodeClass (vtkMRMLScene constructor)
2. qSlicerMainWindow initialization - layout manager creates new node - no default node yet present, thus `node->Reset(defaultNode);` is not called
3. Initialization of the window object derived from qSlicerMainWindow - I set a new layout here - the layout manager creates a new node - no default node yet present, thus `node->Reset(defaultNode);` is not called
4. In `vtkMRMLLayoutLogic::CreateMissingViews` the node is set to the scene, which leads to `vtkMRMLViewLogic::UpdateViewNode()` that tries to get the view node of the scene which fits to its name, however does not find one. So it creates a new vtkMRMLViewNode for itself and also adds this node to the scene. The name is auto-generated: “View”.
5. A new scene for vtkSlicerunitsLogic is created ( RegisterNodeClass (vtkMRMLScene constructor) )
6. postInitializeApplication: default 3d view node is created while loading the module ‘ViewControllers’ and set to the scene. Only the settings `BoxVisibility, AxisLabelsVisibility, UseOrthographicProjection, UseDepthPeeling, OrientationMarkerType, OrientationMarkerSize, RulerType` are read from QSettings and set to the default node. Maybe it would be worth to read also other settings from the QSettings. All present views are then reset to the default node.

What I did to solve my problem was to make the following connection in my main window:

```auto
Q_Q(MyMainWindow);
QObject::connect(q, SIGNAL(initialWindowShown()), q, SLOT(startupCompleted()));

```

with

```auto
void MyMainWindow::startupCompleted()
{
    qSlicerApplication * app = qSlicerApplication::application();
    std::vector<vtkMRMLNode*> nodes;
    app->mrmlScene()->GetNodesByClass("vtkMRMLViewNode", nodes);
    nodes.push_back(app->mrmlScene()->GetDefaultNodeByClass("vtkMRMLViewNode"));
    
    for (auto&& node : nodes)
    {
        vtkMRMLViewNode* viewNode = vtkMRMLViewNode::SafeDownCast(node);
        int wasModifying = viewNode->StartModify();
        viewNode->SetBackgroundColor(0.0f, 0.0f, 0.0f);
        viewNode->SetBackgroundColor2(0.0f, 0.0f, 0.0f);
        viewNode->SetBoxVisible(false);
        viewNode->SetAxisLabelsVisible(false);
        viewNode->EndModify(wasModifying);
    }
}

```

This works now, the settings are correctly taken over. However, I suspect a malfunction here in the Slicer code. The standard vtkMRMLViewNode that is created at Slicer startup is called View1, so this is clearly step 2 in the list above. The third (step 3) is created by my layout change request. The fourth creation, however, is suspicious to me. Maybe there is a mixup between Name, SingletonTag, and LayoutLabel? Here the fields of the nodes for comparison:

**NodeFromStep3**  
Name: Viewcx3dView (probably generated based on the SingletonTag)  
SingletonTag: cx3dView (correct according to my layout definition)  
LayoutLabel: 3D view (correct according to my layout definition)

**NodeFromStep4**  
Name: View (autogenerated)  
SingletonTag: 3D view (from my LayoutLabel?)  
LayoutLabel: 1 (autogenerated?)

Moreover, when I do the following:

```auto
vtkMRMLViewLogic* ViewLogic = layoutManager->threeDWidget("Viewcx3dView")->viewLogic();
vtkMRMLViewNode* ViewNode1 = layoutManager->threeDWidget("Viewcx3dView")->mrmlViewNode();
vtkMRMLViewNode* ViewNode2 = ViewLogic->GetViewNode();

```

then `ViewNode1` is **NodeFromStep3** and `ViewNode2` is **NodeFromStep4**. Is this how it should be?

Best,  
Robert

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 30, 2019, 1:39pm UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/4 "2019-07-30T13:39:52Z")

</div>

> [@rprueckl](#):
>
> What I did to solve my problem was to make the following connection in my main window

As soon as the scene is created, you can define default view nodes with modified properties (see and follow [this pattern](https://github.com/Slicer/Slicer/blob/1cff95e84339e70649841f34479cc6daded7700b/Modules/Loadable/ViewControllers/Logic/vtkSlicerViewControllersLogic.cxx#L86-L102)). So, you should be able to do just before you register and set your custom layout, no need to add a callback function for this.

> [@rprueckl](#):
>
> then `ViewNode1` is **NodeFromStep3** and `ViewNode2` is **NodeFromStep4**. Is this how it should be?

I agree that this is somewhat complicated but it probably works correctly. [`threeDWidget(QString)`](https://apidocs.slicer.org/master/classqMRMLLayoutManager.html#a810df79c97d1772d995de70b9e4b442d) is a convenience method that returns widget by name. If you have multiple view nodes by the same name then you will get the first view with matching name. To get view nodes that are used in the current layout, you can iterate through all view nodes in the scene and only use those that are [mapped in current layout](https://apidocs.slicer.org/master/classvtkMRMLAbstractViewNode.html#a9f5f661e2310e58753e4a63c4891e02e).

---

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [July 30, 2019, 7:33pm UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/5 "2019-07-30T19:33:38Z")

</div>

> [@lassoan](#):
>
> As soon as the scene is created, you can define default view nodes with modified properties (see and follow [this pattern](https://github.com/Slicer/Slicer/blob/1cff95e84339e70649841f34479cc6daded7700b/Modules/Loadable/ViewControllers/Logic/vtkSlicerViewControllersLogic.cxx#L86-L102)).

This kind of works. It sets the background black, but for the Box and AxisLabels the result is as follows:  
 ![Unbenannt](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/b/c/bc7c462cb2faafb1277b081024a4f579f6d68f88.png)  
Not sure why this happens.

> [@lassoan](#):
>
> If you have multiple view nodes by the same name then you will get the first view with matching name.

Well, this is not the case. I looked at the following parts of the code:  
[https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Widgets/qMRMLLayoutManager.cxx#L133](https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Widgets/qMRMLLayoutManager.cxx#L133)  
and  
[https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Widgets/qMRMLLayoutManager.cxx#L378](https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Widgets/qMRMLLayoutManager.cxx#L378)

and encountered that for the `threeDView` the `LayoutLabel` is taken as the name of the logic (it is set in the method `setViewLabel`) whereas for the slice view, there is a separate method (`setSliceViewName` in line 376) which sets the `LayoutName` to the logic. In both cases, however, the logic tries to find the respective node by its name:  
[https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Logic/vtkMRMLSliceLogic.cxx#L326](https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Logic/vtkMRMLSliceLogic.cxx#L326)  
and  
[https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Logic/vtkMRMLViewLogic.cxx#L351](https://github.com/Slicer/Slicer/blob/69d0f7d9b71ece1d987f9ed665015687cbbe154c/Libs/MRML/Logic/vtkMRMLViewLogic.cxx#L351)

So, as an experiment, I implemented also for the `qMRMLThreeDWidget` a separate method `setViewName`, which is used by the `qMRMLLayoutThreeDViewFactory` to set the name of the logic according to the `LayoutName` and removed setting the logic name from `setViewLabel`. Now, the previously created additional view node (and also an additional camera node that was created) is not created anymore. This is how I would have expected it to be. Of course I am not sure if I miss side effects here or if there was some reason for the different implementations.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 30, 2019, 10:14pm UTC](https://discourse.slicer.org/t/changing-the-background-of-3d-view-at-startup/7798/6 "2019-07-30T22:14:48Z")

</div>

Thank you for digging into this!

You are right, it is indeed incorrect in qMRMLThreeDViewControllerWidget that view logic name is set based on layout _label_ instead of layout _name_. Probably it did not come up as an error before because in built-in view layouts, layout name and label are always the same for 3D views. I’ve fixed the issue and I’ll push a fix today if no complications come up during testing.
