Best practice for accessing ScriptedLoadableModuleLogic from Module?

Operating system: Windows 10
Slicer version:5.2.1

I have created my own ScriptedLoadableModule. It has a Module, Widget and Logic. In the documentation I see that the Module is supposed to create the Widget and Logic (https://www.slicer.org/w/img_auth.php/7/79/SlicerModulesProgrammingBeyondBasics.pdf). But I don’t think I’ve ever seen that in examples. In most cases the Module doesn’t interact with the Widget at all, both seem to get created automatically. Normally I’ve seen the Widget create the Logic, for example in the template: Slicer/ScriptedLoadableModuleTemplate.py at main · Slicer/Slicer · GitHub. Is the Module really supposed to create both? Is there an example of that? (or maybe that’s how it happens under the hood)

My issue is I have implemented onURLReceived like in the DICOM module Slicer/DICOM.py at main · Slicer/Slicer · GitHub, which is in the Module (I think because Widget may not have been loaded by the time URL event is triggered?). But I need to access the Logic instance to respond to the URL event (I want to access Logic instance to get parameter node which will be shared with Widget). If I create the Logic instance in the Module how do I give it to the Widget, since most of the time the Widget seems to create the Logic? I could create 2 instances of Logic and since they will share a singleton parameter node it would probably all work out but doesn’t feel right.

I can only find this one example using the URL event but maybe there are other examples that show how a Module can access a parameter node/Logic instance, that would be helpful.

2 Likes

For a scripted loadable module, the module class will automatically create the widget based on the class name (MyModule, MyModuleWidget). You don’t need to add any code to the base Module class for this.

As mentioned on one of the slides “Current limitation: Scripted module logic is not created automatically, it has to be instantiated in the Widget class.” So as seen in the template the logic is instantiated in the widget class. (self.logic = MyModuleLogic())

If there are issues during startup loading order, they can usually be mitigated by utilizing the startupCompleted signal. See linked thread:

1 Like

Thanks for the reply James. So I understand that you are suggesting I create the Logic in the Module. But if I do that how do I pass that same Logic instance to the Widget? Since the Widget creation is automatic I don’t have access to the constructor or, as far as I can tell, the Widget instance. But I would need that if I was to pass along the Logic instance.

Perhaps the following thead title would be more complete: Best practice for accessing the same ScriptedLoadableModuleLogic instance from Module and Widget?

An instance of the logic class is created from the init of the widget class. Typically there is nothing else in the “MyModule” class other than the info setting the title, category, contributors, etc. When you are creating a module, the custom code that you add is typically part of the Widget or Logic classes. So far I’m not aware of any typical usage that attempts to use a logic class from within a Module class. It is typically only used in Widget or Logic classes.

class MyModule(ScriptedLoadableModule):
    """Uses ScriptedLoadableModule base class, available at:
    https://github.com/Slicer/Slicer/blob/main/Base/Python/slicer/ScriptedLoadableModule.py
    """

    def __init__(self, parent):
        ScriptedLoadableModule.__init__(self, parent)
        self.parent.title = "ScriptedLoadableModuleTemplate"  # TODO make this more human readable by adding spaces
        self.parent.categories = ["Examples"]
        self.parent.dependencies = []
        self.parent.contributors = ["John Doe (AnyWare Corp.)"]  # replace with "Firstname Lastname (Organization)"
        self.parent.helpText = """
This is an example of scripted loadable module bundled in an extension.
It performs a simple thresholding on the input volume and optionally captures a screenshot.
"""
        self.parent.helpText += self.getDefaultModuleDocumentationLink()
        self.parent.acknowledgementText = """
This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
and Steve Pieper, Isomics, Inc. and was partially funded by NIH grant 3P41RR013218-12S1.
"""  # replace with organization, grant and thanks.

class MyModuleWidget(ScriptedLoadableModuleWidget):
  def __init__(self, parent=None):
    ScriptedLoadableModuleWidget.__init__(self, parent)
    self.logic = MyModuleLogic()

class MyModuleLogic(ScriptedLoadableModuleLogic):
...