SOLVED How to pass a value from GeDialog to another class

This is probably a silly question, but I'm stuck and need some help so I can move forward in my plugin without using global dialog.
The original dialog has much more checkboxes and edit texts to guide the whole processing, but I've been able to get a very simplified sample of my code with a similar structure.

I have a class

class processing

that needs to retrieve data from the dialog in order to process the script, but I really don't know how to get it since the code below is returning this error:

AttributeError: 'OptionsDialog' object has no attribute 'print_msg1'

I have to keep the structure like it is at the moment.

This the sample, any help would be awesome:

import c4d

pluginVersion = "v1.0.0"
pluginName = "Get Value From Dialog"
PLUGIN_ID = 1111222

class OptionsDialog (c4d.gui.GeDialog):
    GROUP_OPTIONS = 1011
    CHKBX1 = 1007
    CHKBX2 = 1008
    CHKBX3 = 1009
    BTN_OK = 1010
    def __init__(self):
        self._hasBeenInitalized = False
        self._hasLayoutDone = False

    def Message(self, msg, result):
        if msg.GetId() == c4d.BFM_ACTION: msg[c4d.BFM_ACTION_VALUE]        
        return c4d.gui.GeDialog.Message(self, msg, result)
    
    def CreateLayout(self):
        self.SetTitle(pluginName + ' ' + pluginVersion)
        self.AddCheckbox(self.CHKBX1, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 1')
        self.AddCheckbox(self.CHKBX2, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 2')
        self.AddCheckbox(self.CHKBX3, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 3')
        if self.GroupBegin(self.GROUP_OPTIONS, c4d.BFH_CENTER, 1, 1):
            self.AddButton(self.BTN_OK, c4d.BFH_SCALEFIT,  initw=500, inith=15,name='Go!')
        self.GroupEnd()
        self._hasLayoutDone = True
        self._hasBeenInitalized = False
        return True

    def Command(self, id, msg):
        if id==self.BTN_OK or id==c4d.IDC_OK:
            self.print_msg1 = self.GetBool(self.CHKBX1)
            self.print_msg2 = self.GetBool(self.CHKBX2)
            self.print_msg3 = self.GetBool(self.CHKBX3)
            self.Run()
        return True

    def InitValues(self):
        if self._hasBeenInitalized is True:
            return True
        self.SetBool(self.CHKBX1, True)
        self._hasBeenInitalized = True
        return True

    def Run(self):
        message = processing().set_nice_message()
        print(message)
        c4d.EventAdd()
        return True

class processing:
    dlg = OptionsDialog()
    def set_nice_message(self):

        """ how can I get values from OptionsDialog() ???
        """
        if self.dlg.print_msg1: result = 'Hello world 1'
        if self.dlg.print_msg2: result = 'Hello world 2'
        if self.dlg.print_msg3: result = 'Hello world 3'
        return result

class DialogCommandData(c4d.plugins.CommandData):
    dlg = None

    def Execute(self, doc):
        if self.dlg is None:
            self.dlg = OptionsDialog()
        return self.dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC,
                                 pluginid=PLUGIN_ID,
                                 xpos=-2, ypos=-2, defaultw=720, defaulth=50)

    def RestoreLayout(self, secret):
        if self.dlg is None:
            self.dlg = OptionsDialog()
        return self.dlg.Restore(pluginid=PLUGIN_ID, secret=secret)


if __name__ == '__main__':
    myPlugin = DialogCommandData()
    c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                str=pluginName,
                                info=0,
                                icon=None,
                                help=pluginName,
                                dat=myPlugin)

First of all, your dialog in the class processing is never used. So, you never open it or pass it or receive it from somewhere else. It just is generated, and then ... exists. Thus, the attempts in set_nice_message to read the print_msg attributes must fail... as these attributes are only generated when you press the OK button, and the class's local dialog is not open.

Remove the OptionsDialog() from the class processing.
Pass the actual dialog in the parameter list of set_nice_message.
Consequentially, remove the self.dlg from the body of that method, and replace it by the parameter.
In Run(), pass self (the real, actual dialog that is currently open) to set_nice_message().

First of all, your dialog in the class processing is never used. So, you never open it or pass it or receive it from somewhere else. It just is generated, and then ... exists. Thus, the attempts in set_nice_message to read the print_msg attributes must fail... as these attributes are only generated when you press the OK button, and the class's local dialog is not open.

Remove the OptionsDialog() from the class processing.
Pass the actual dialog in the parameter list of set_nice_message.
Consequentially, remove the self.dlg from the body of that method, and replace it by the parameter.
In Run(), pass self (the real, actual dialog that is currently open) to set_nice_message().

@cairyn thanks for your time and helpful answer.
I was trying to retrieve the value of a variable from another class by calling it directly. This is why you could see OptionsDialog() within class processing. This is the source of my problems, because as far as I know, this is how a class variable should be called from another class.
Probably I'm wrong or things are different when there's a dialog involved 😕

Anyways, this is the working code, with your solution addressed:

import c4d

pluginVersion = "v1.0.0"
pluginName = "Get Value From Dialog"
PLUGIN_ID = 1111222

class OptionsDialog (c4d.gui.GeDialog):
    GROUP_OPTIONS = 1011
    CHKBX1 = 1007
    CHKBX2 = 1008
    CHKBX3 = 1009
    BTN_OK = 1010
    def __init__(self):
        self._hasBeenInitalized = False
        self._hasLayoutDone = False

    def Message(self, msg, result):
        if msg.GetId() == c4d.BFM_ACTION: msg[c4d.BFM_ACTION_VALUE]        
        return c4d.gui.GeDialog.Message(self, msg, result)
    
    def CreateLayout(self):
        self.SetTitle(pluginName + ' ' + pluginVersion)
        self.AddCheckbox(self.CHKBX1, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 1')
        self.AddCheckbox(self.CHKBX2, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 2')
        self.AddCheckbox(self.CHKBX3, c4d.BFH_SCALEFIT, initw=1, inith=1, name='Checkbox 3')
        if self.GroupBegin(self.GROUP_OPTIONS, c4d.BFH_CENTER, 1, 1):
            self.AddButton(self.BTN_OK, c4d.BFH_SCALEFIT,  initw=500, inith=15,name='Go!')
        self.GroupEnd()
        self._hasLayoutDone = True
        self._hasBeenInitalized = False
        return True

    def Command(self, id, msg):
        if id==self.BTN_OK or id==c4d.IDC_OK:
            self.print_msg1 = self.GetBool(self.CHKBX1)
            self.print_msg2 = self.GetBool(self.CHKBX2)
            self.print_msg3 = self.GetBool(self.CHKBX3)
            self.Run()
        return True

    def InitValues(self):
        if self._hasBeenInitalized is True:
            return True
        self.SetBool(self.CHKBX1, True)
        self._hasBeenInitalized = True
        return True

    def Run(self):
        message = processing().set_nice_message(self.print_msg1, self.print_msg2, self.print_msg3)
        print(message)
        c4d.EventAdd()
        return True

class processing:
    def set_nice_message(self, msg1, msg2, msg3):
        if msg1: result = 'Hello world 1'
        if msg2: result = 'Hello world 2'
        if msg3: result = 'Hello world 3'
        return result

class DialogCommandData(c4d.plugins.CommandData):
    dlg = None

    def Execute(self, doc):
        if self.dlg is None:
            self.dlg = OptionsDialog()
        return self.dlg.Open(dlgtype=c4d.DLG_TYPE_ASYNC,
                                 pluginid=PLUGIN_ID,
                                 xpos=-2, ypos=-2, defaultw=720, defaulth=50)

    def RestoreLayout(self, secret):
        if self.dlg is None:
            self.dlg = OptionsDialog()
        return self.dlg.Restore(pluginid=PLUGIN_ID, secret=secret)

if __name__ == '__main__':
    myPlugin = DialogCommandData()
    c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                str=pluginName,
                                info=0,
                                icon=None,
                                help=pluginName,
                                dat=myPlugin)

Hello @danielsian,

Thank you for reaching out to us. It is good to hear that you have found a working solution. For future readers I want to emphasize however a few points.

  1. A GeDialog is a Python object like any other you can just pass it around. Either inside a method of that dialog and by passing out self, i.e., the instance of the dialog. Or in the place where you did instantiate/attached your dialog, i.e. DialogCommandData in your case.
  2. set_nice_message is only formally a method of processing as it does not make use of the object instance self. You should either make the method a module function (i.e., a function without a class) or add the @staticmethod decorator, so that you do not have to insatiate a processing instance every time you want to call it, e.g., here message = processing().set_nice_message(self.print_msg1, self.print_msg2, self.print_msg3) .

Find below an example which briefly demonstrates both points.

Cheers,
Ferdinand

The result:

Ran <__main__.Processor object at 0x0000014E8F61CB10> for <__main__.MyDialog object at 0x0000014E8F828010>.
Ran <__main__.Processor object at 0x0000014E8F61CAD0> for <__main__.MyDialog object at 0x0000014E8F828010>.
Ran <__main__.Processor object at 0x0000014E8F61CA90> for <__main__.MyDialog object at 0x0000014E8F828010>.
args: (42,), kwargs: {'object': <__main__.MyDialog object at 0x0000014E8F828010>, 'msg': "bob's your uncle."}
>>> 

The code:

import c4d

class Processor(object):
    """Your processor class
    """
    def Excecute(self, dialog):
        """The execution function of a processor.
        """
        if not isinstance(dialog, c4d.gui.GeDialog):
            raise RuntimeError(f"Expected GeDialog for 'dialog': {dialog}")

        # Do stuff with the dialog ...

        print (f"Ran {self} for {dialog}.")

# Some global processor instances
g_processors = [Processor(), Processor(), Processor()]

class MyDialog(c4d.gui.GeDialog):
    """The dialog which passes itself to all processor executions.
    """
    
    def CallProcessors(self):
        """ The function in the dialog which calls the processors and
        passes the dialog itself.
        """
        # Call all processors.
        for p in g_processors:
            p.Excecute(dialog=self)

        # Call the global function.
        SomeGlobalFunction(42, object=self, msg="bob's your uncle.")


def SomeGlobalFunction(*args, **kwargs):
    """Just prints its arguments.
    """
    print (f"args: {args}, kwargs: {kwargs}")

def main():
    """Entry point.
    """
    dialog = MyDialog()
    dialog.CallProcessors()

if __name__ == '__main__':
    main()

@ferdinand Thank you for your awesome explanation!
I will keep this post as a reference for my studies as your approach seems a bit complicated for my understanding at the moment.
I'm learning a lot with your contribution in this forum, and in this case here it's not gonna be different.
Cheers