How to update the progress bar from a scripted CLI

I added an example to the Python scripting documentation, demonstrating how to use the Slicer Execution Model XML-based (<filter-progress>...</filter-progress>) reporting format from a scripted CLI. Getting the bar to update in realtime requires one small detail, to flush stdout after each update, or else Slicer will not see/parse the output until the CLI completes.

See example code here:

https://www.slicer.org/wiki/Documentation/Nightly/Developers/FAQ/Python_Scripting#How_to_update_progress_bar_in_scripted_.28Python.2C_or_other.29_CLI_modules

2 Likes

@ihnorton As an update to the Python FAQs, one could also add a question on “How to access progress bar of scripted CLI from scripted module”

  • MyModule.py
def createProgressDialog(parent=None, value=0, maximum=100, windowTitle="Processing..."):
    import qt # qt.qVersion()
    progressIndicator = qt.QProgressDialog()  #(parent if parent else self.mainWindow())
    progressIndicator.minimumDuration = 0
    progressIndicator.maximum = maximum
    progressIndicator.value = value
    progressIndicator.windowTitle = windowTitle
    return progressIndicator
      

class MyModuleWidget(ScriptedLoadableModuleWidget, VTKObservationMixin):

    def setup(self)

        parametersFormLayout = qt.QFormLayout(myInputCollapsibleButton)
        self.testButton = qt.QPushButton('Test')
        self.testButton.enabled = True
        self.testButton.clicked.connect(self.onTestButton)
        parametersFormLayout.addRow(self.TestButton)
    
    def onTestButton(self):
        myCli = slicer.modules.tmp2cli
        cliNode = None
        myInt = 100
        cliNode = slicer.cli.run(myCli, cliNode, {'myString': 'hello World', 'myInt':100} )
        cliNode.AddObserver('ModifiedEvent', self.onCliModified)
        self.progressBar = myUtil.createProgressDialog(None, 0, myInt)
    
    def onCliModified(self, caller, event):
        self.progressBar.setValue(caller.GetProgress())
        if caller.GetStatus() == 32: 
            self.progressBar.close()
  • MyModuleCLI.py
#!/usr/bin/env python-real

import os
import sys
import time

def main(params):
    myString = params[1]
    myint = params[3]

    print("""<filter-start><filter-name>TestFilter</filter-name><filter-comment>ibid</filter-comment></filter-start>""")
    sys.stdout.flush()

    for i in range(0,myint):
        print("""<filter-progress>{}</filter-progress>""".format(i/float(myint)))
        sys.stdout.flush()
        time.sleep(0.5)

    print("""<filter-end><filter-name>TestFilter</filter-name><filter-time>{}</filter-time></filter-end>""".format(myint))
    sys.stdout.flush()

if __name__ == "__main__":
    print (' ===================== ', len(sys.argv))
    for id, each in enumerate(sys.argv):
        print (' - sys.argv[{}] = {}'.format(id, each))
    if len(sys.argv) > 1:
        main(sys.argv[1:])

Thanks a lot, I’ve added it here:

1 Like