# Updated sample code for calling CLI via C++

**URL:** https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840
**Category:** Development
**Created:** [August 1, 2019, 6:14pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840 "2019-08-01T18:14:09Z")
**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: [August 1, 2019, 6:14pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/1 "2019-08-01T18:14:09Z")

</div>

Hello,  
below is an updated example that shows how to call a CLI module from C++. I used the code from the link, but it seems to be quite old. So, i you want an update, please take my code (with any modification).

[https://www.slicer.org/wiki/Documentation/Nightly/Developers/SlicerExecutionModel/Programmatic\_Invocation](https://www.slicer.org/wiki/Documentation/Nightly/Developers/SlicerExecutionModel/Programmatic_Invocation)

```auto
void MyWidget::generate3dModel()
{
    Q_D(MyWidget);
    vtkMRMLScene* scene = qSlicerCoreApplication::application()->mrmlScene();

    // get module and its widget
    qSlicerCLIModule* cliModule = static_cast<qSlicerCLIModule*>(qSlicerCoreApplication::application()->moduleManager()->module("GrayscaleModelMaker"));
    qSlicerCLIModuleWidget *cliWidget = static_cast<qSlicerCLIModuleWidget*>(cliModule->widgetRepresentation());
    vtkSlicerCLIModuleLogic* moduleLogic = vtkSlicerCLIModuleLogic::SafeDownCast(cliModule->logic());

    // get/create CLI module node
    vtkMRMLCommandLineModuleNode* cliNode = moduleLogic->CreateNodeInScene();

    // get/create output node
    QString outputNodeID(this->volumeNode()->GetID());
    outputNodeID += "Model";
    vtkMRMLModelNode* outputNode = vtkMRMLModelNode::SafeDownCast(scene->GetFirstNodeByName(outputNodeID.toStdString().c_str()));
    if (!outputNode)
    {
        outputNode = vtkMRMLModelNode::SafeDownCast(scene->CreateNodeByClass("vtkMRMLModelNode"));
        outputNode->SetName(outputNodeID.toStdString().c_str());
        
        // Add node to the scene
        scene->AddNode(outputNode);
        outputNode->Delete();
    }

    // extract threshold from volume display node
    vtkMRMLScalarVolumeDisplayNode* VolumeDisplayNode = vtkMRMLScalarVolumeDisplayNode::SafeDownCast(this->volumeNode()->GetDisplayNode());
    double threshold = VolumeDisplayNode->GetLowerThreshold();
    
    // set parameters
    cliNode->SetParameterAsNode("InputVolume", this->volumeNode());
    cliNode->SetParameterAsNode("OutputGeometry", outputNode);
    cliNode->SetParameterAsFloat("Threshold", threshold);
    cliNode->SetParameterAsString("Name", outputNodeID.toStdString().c_str());
    cliNode->SetParameterAsInt("Smooth", 15); // default
    cliNode->SetParameterAsFloat("Decimate", 0.25f); // default
    cliNode->SetParameterAsBool("SplitNormals", true); // default
    cliNode->SetParameterAsBool("PointNormals", true); // default

    // connect cli widget with cli module node
    cliWidget->setCurrentCommandLineModuleNode(cliNode);

    // Connect node modified event to the update the progress bar and to proceed to the next step
    this->qvtkConnect(cliNode, vtkCommand::ModifiedEvent, this, SLOT(on3dModelGenerationProgress(vtkObject*)));

    // start via logic
    moduleLogic->Apply(cliNode);
}

void MyWidget::on3dModelGenerationProgress(vtkObject* cliNode)
{
    Q_D(MyWidget);

    vtkMRMLCommandLineModuleNode * node = vtkMRMLCommandLineModuleNode::SafeDownCast(cliNode);
    if (node)
    {
        // Update Progress
        ModuleProcessInformation* info = node->GetModuleDescription().GetProcessInformation();
        switch (node->GetStatus())
        {
        case vtkMRMLCommandLineModuleNode::Cancelled:
            d->cliProgressBar->setMaximum(0);
            break;
        case vtkMRMLCommandLineModuleNode::Scheduled:
            d->cliProgressBar->setMaximum(0);
            break;
        case vtkMRMLCommandLineModuleNode::Running:
            d->cliProgressBar->setMaximum(info->Progress != 0.0 ? 100 : 0);
            d->cliProgressBar->setValue(info->Progress * 100.);
            break;
        case vtkMRMLCommandLineModuleNode::Completed:
        case vtkMRMLCommandLineModuleNode::CompletedWithErrors:
            d->cliProgressBar->reset();
            this->qvtkDisconnect(cliNode, vtkCommand::ModifiedEvent, this, SLOT(on3dModelGenerationProgress(vtkObject*)));
            break;
        default:
        case vtkMRMLCommandLineModuleNode::Idle:
            d->cliProgressBar->reset();
            break;
        }
    }
}

```

I have one question to this: where would be the right place to remove the vtkMRMLCommandLineModuleNode again after execution? I tried to remove it in the `case vtkMRMLCommandLineModuleNode::Completed:` case, but the program crashed…

---

<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: [August 1, 2019, 9:26pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/2 "2019-08-01T21:26:21Z")

</div>

The VTK object that invoked an event should not be deleted in the callback of that event. You can set a single-shot QTimer with 0 timeout to clean up the temporary nodes after the callback is completed.

---

<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: [August 2, 2019, 12:45pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/3 "2019-08-02T12:45:19Z")

</div>

I updated the code slightly (removed my own callback and used qSlicerCLIProgressBar):

```auto
Q_D(CxScalarVolumeDisplayWidget);
    vtkMRMLScene* scene = qSlicerCoreApplication::application()->mrmlScene();

    // get module and its widget
    qSlicerCLIModule* cliModule = static_cast<qSlicerCLIModule*>(qSlicerCoreApplication::application()->moduleManager()->module("GrayscaleModelMaker"));
    qSlicerCLIModuleWidget *cliWidget = static_cast<qSlicerCLIModuleWidget*>(cliModule->widgetRepresentation());
    vtkSlicerCLIModuleLogic* moduleLogic = vtkSlicerCLIModuleLogic::SafeDownCast(cliModule->logic());

    if (!d->cliNode)
    {
        // create CLI module node
        d->cliNode = moduleLogic->CreateNodeInScene();
        d->cliNode->Register(d);

        // get/create output node
        QString outputNodeID(this->volumeNode()->GetID());
        outputNodeID += "Model";
        vtkMRMLModelNode* outputNode = vtkMRMLModelNode::SafeDownCast(scene->GetFirstNodeByName(outputNodeID.toStdString().c_str()));
        if (!outputNode)
        {
            outputNode = vtkMRMLModelNode::SafeDownCast(scene->CreateNodeByClass("vtkMRMLModelNode"));
            outputNode->SetName(outputNodeID.toStdString().c_str());
        
            // Add node to the scene
            scene->AddNode(outputNode);
            outputNode->Delete();
        }

        // extract threshold from volume display node
        vtkMRMLScalarVolumeDisplayNode* VolumeDisplayNode = vtkMRMLScalarVolumeDisplayNode::SafeDownCast(this->volumeNode()->GetDisplayNode());
        double threshold = VolumeDisplayNode->GetLowerThreshold();
    
        // set parameters
        d->cliNode->SetParameterAsNode("InputVolume", this->volumeNode());
        d->cliNode->SetParameterAsNode("OutputGeometry", outputNode);
        d->cliNode->SetParameterAsFloat("Threshold", threshold);
        d->cliNode->SetParameterAsString("Name", outputNodeID.toStdString().c_str());
        d->cliNode->SetParameterAsInt("Smooth", 15); // default
        d->cliNode->SetParameterAsFloat("Decimate", 0.25f); // default
        d->cliNode->SetParameterAsBool("SplitNormals", true); // default
        d->cliNode->SetParameterAsBool("PointNormals", true); // default

        // connect cli widget with cli module node
        cliWidget->setCurrentCommandLineModuleNode(d->cliNode);

        // connect to qSlicerCLIProgressBar
        progressBar->setCommandLineModuleNode(d->cliNode);

        // start via logic
        moduleLogic->Apply(d->cliNode);
    }

```

---

<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: [August 2, 2019, 2:43pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/4 "2019-08-02T14:43:17Z")

</div>

Thank you for sharing this.

It is an important design principle that all processing must be implemented in a module’s logic class, and not in the user interface. This decoupling of GUI from logic allows performing batch processing (without instantiating GUI) or using a module from another module. There are a few more similar principles - see development tutorial [here](https://www.slicer.org/wiki/Documentation/Nightly/Training#PerkLab.27s_Slicer_bootcamp_training_materials).

Therefore, a few suggestions:

- Do not retreive or use cliWidget. A module’s widget should never be used from another module.
- Node ID gets assigned automatically when a node is added to the scene and must not be get or set manually. To create an output model node, add it to the scene, and retrieve the object point, use `vtkMRMLNode* outputModelNode = scene->AddNewNodeByClass("vtkMRMLModelNode");` (this single line replaces 5-10 lines in your code)
- All data processing should happen in your module logic, not in the GUI (widget) class, so move `Generate3dModel` method to your module logic and call that method from the GUI. See for example how it is done in [Crop Volume module](https://github.com/Slicer/Slicer/blob/b0a932cc4b3a9d674c64f37a13a3b47144274b69/Modules/Loadable/CropVolume/Logic/vtkSlicerCropVolumeLogic.cxx#L415-L416). If you need progress bar or execution in the background then you can return the created CLI module node to the caller.

Trivial: There is no “Name” parameter of Grayscale Model Maker module, so you can remove setting of that parameter.

---

<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: [August 6, 2019, 11:31am UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/5 "2019-08-06T11:31:13Z")

</div>

Thanks for elaborating on this.

- I removed the cliWidget (it was a remainder from the initial sample code, which used a vtkCommandLineModuleGUI)
- I replaced the code for creating the output node
- I moved the code to the logic object
- The Grayscale Model Maker lists a parameter called Name, therefore I tried to use it:

> <https://github.com/Slicer/Slicer/blob/079457fcce6ee3263210059d2a9bff66981fde2b/Modules/CLI/GrayscaleModelMaker/GrayscaleModelMaker.xml#L40-L47>

A minimalistic example could look like this:

```auto
vtkMRMLScene* scene = qSlicerCoreApplication::application()->mrmlScene();

// get module and its logic
qSlicerCLIModule* cliModule = static_cast<qSlicerCLIModule*>(qSlicerCoreApplication::application()->moduleManager()->module("GrayscaleModelMaker"));
vtkSlicerCLIModuleLogic* moduleLogic = vtkSlicerCLIModuleLogic::SafeDownCast(cliModule->logic());

// create CLI module node
vtkMRMLCommandLineModuleNode* cliNode = moduleLogic->CreateNodeInScene();

// get/create output node
vtkMRMLModelNode* outputNode = vtkMRMLModelNode::SafeDownCast(scene->AddNewNodeByClass("vtkMRMLModelNode", "modelName"));

// extract threshold from volume display node
vtkMRMLScalarVolumeDisplayNode* VolumeDisplayNode = vtkMRMLScalarVolumeDisplayNode::SafeDownCast(volumeNode->GetDisplayNode());
double threshold = VolumeDisplayNode->GetLowerThreshold();

// set parameters
cliNode->SetParameterAsNode("InputVolume", volumeNode);
cliNode->SetParameterAsNode("OutputGeometry", outputNode);
cliNode->SetParameterAsFloat("Threshold", threshold);

// start via logic
moduleLogic->Apply(cliNode);

```

---

<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: [August 6, 2019, 3:04pm UTC](https://discourse.slicer.org/t/updated-sample-code-for-calling-cli-via-c/7840/6 "2019-08-06T15:04:53Z")

</div>

Thank you, I’ve updated example in the [Slicer wiki](https://www.slicer.org/wiki/Documentation/Nightly/Developers/SlicerExecutionModel/Programmatic_Invocation#C.2B.2B_example) (with some changes that show how processing should be implemented in the module logic).
