Thank you for the hint Andras, that helped me solve it.
I found out the following sequence of vtkMRMLViewNode creations:
- Creation of qSlicerApplication - RegisterNodeClass (vtkMRMLScene constructor)
- qSlicerMainWindow initialization - layout manager creates new node - no default node yet present, thus
node->Reset(defaultNode);
is not called
- 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
- 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”.
- A new scene for vtkSlicerunitsLogic is created ( RegisterNodeClass (vtkMRMLScene constructor) )
- 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:
Q_Q(MyMainWindow);
QObject::connect(q, SIGNAL(initialWindowShown()), q, SLOT(startupCompleted()));
with
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:
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