Solved How to Communicate between SubDialog and main GeDialog

Hello,
I am trying to send messages from a SubDialog to a parent GeDialog. I am using a variation of this example implementation from NiklasR.

import c4d

PLUGIN_ID = 1000004 # Test ID
ACTION_ID = 123456

class MainDialog(c4d.gui.GeDialog):
    @property
    def sub_dialog(self):
        if not hasattr(self, '_sub_dialog'):
            self._sub_dialog = SubDialog()
        return self._sub_dialog

    def CreateLayout(self):
        self.SetTitle('Main Dialog')
        self.AddButton(1000, 0, name="Open Sub-Dialog")
        return True

    def Message(self, msg, result):
        if msg.GetId() == ACTION_ID:
            print msg
        return c4d.gui.GeDialog.Message(self, msg, result)

    def Command(self, param, bc):
        print bc
        if param == 1000:
            self.sub_dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, subid=1)
        return True

    def Restore(self, pluginid, secref):
        if secref['subid'] == 1:
            return self.sub_dialog.Restore(pluginid, secref)
        else:
            return super(MainDialog, self).Restore(pluginid, secref)

class SubDialog(c4d.gui.GeDialog):
    def CreateLayout(self):
        self.SetTitle('Sub-Dialog')
        self.AddButton(1000, 0, name="Send Message")
        return True

    def Command(self, id, msg):
        if id == 1001:
            bc = c4d.BaseContainer()
            bc.SetId(c4d.BFM_ACTION)
            bc.SetInt32(c4d.BFM_ACTION_ID, ACTION_ID)
            self.SendParentMessage(bc)
        return True

class Command(c4d.plugins.CommandData):

    def Register(self):
        return c4d.plugins.RegisterCommandPlugin(
                PLUGIN_ID, "Sub-Dialog Message", 0, None, "", self)

    @property
    def dialog(self):
        if not hasattr(self, '_dialog'):
            self._dialog = MainDialog()
        return self._dialog

    def Execute(self, doc):
        return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID)

    def RestoreLayout(self, secref):
        return self.dialog.Restore(PLUGIN_ID, secref)

if __name__ == '__main__':
    Command().Register()


I've tried using SendParentMessage but, for whatever reason, my parent dialog isn't receiving the message.

In my parent GeDialog I've tried using the Command and Message methods, but neither receives the message from the SubDialog.

Can anyone help? Thank you!

Did you try my example which exactly demonstrate the use of a SubDialog?
SubDialog is about having a dialog embedded into another one.

If you want to make communicate two independent GeDialog you have to use CoreMessage because there is no hierarchy between them they are both independent windows.

Hi @blastframe the main issue I guess is because of your SubDialog inherit from GeDial and not SubDialog.
Here a quick example

import c4d

GADGET_ID_SUBDIALOG = 10000
MSG_ID_SUBDIALOG_LAYOUT_CREATED = 1000001


class SubDialogExample(c4d.gui.SubDialog):

    def CreateLayout(self):
        """
        This Method is called automatically when Cinema 4D Create the Layout (display) of the SubDialog.
        """

        # Creates a Static Text
        self.AddStaticText(1000, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 0, 0, "First Sub Dialog", c4d.BORDER_THIN_IN)
        msgContainer = c4d.BaseContainer(MSG_ID_SUBDIALOG_LAYOUT_CREATED)
        self.SendParentMessage(msgContainer)

        return True


class ExampleDialog(c4d.gui.GeDialog):

    # The SubDialog need to be stored somewhere, we will need this instance to be attached to the current Layout
    subDialog = SubDialogExample()

    def CreateLayout(self):
        """
        This Method is called automatically when Cinema 4D Create the Layout (display) of the Dialog.
        """

        # Adds a Gadget that will host a SubDialog
        self.AddSubDialog(GADGET_ID_SUBDIALOG, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 100, 100)

        # Attaches the stored SubDialog to the Gadget previously created
        self.AttachSubDialog(self.subDialog, GADGET_ID_SUBDIALOG)

        return True

    
    def Message(self, msg, result):
        """
        This Method is called automatically when the GeDialog receives a Message.
        :param msg: The message container.
        :param result: A container to place results in.
        """

        # Messages is sent from the GeUserArea in line 65
        if msg.GetId() == MSG_ID_SUBDIALOG_LAYOUT_CREATED:
            print("The GeUserArea, has been draw.")
            return True

        return super(ExampleDialog, self).Message(msg, result)


def main():
    # Creates a new instance of the GeDialog
    dlg = ExampleDialog()

    # Opens the GeDialog, since it's open it as Modal, it block Cinema 4D
    dlg.Open(c4d.DLG_TYPE_MODAL_RESIZEABLE, defaultw=300, defaulth=50)


if __name__ == "__main__":
    main()

Cheers,
Maxime.

@m_adam Hi Maxime, thank you for the reply.

I wasn't able to get it to work. I would like the Subdialog to be its own window, not attached to the Main Dialog. Is this possible? In the documentation for SendParentMessage it says the method is available for GeDialog but is it only for usage with GeUserArea? I don't think I understand the purpose of the Subdialog when used as a gadget. I see in the documentation for Subdialog that it inherits from GeDialog so shouldn't it be able to open as such? Thank you.

import c4d

PLUGIN_ID = 1000004 # Test ID
ACTION_ID = 123456
GADGET_ID_SUBDIALOG = 10000

class SubDialog(c4d.gui.SubDialog):
    def CreateLayout(self):
        self.SetTitle('Sub-Dialog')
        self.AddButton(1001, 0, name="Send Message")
        return True

    def Command(self, id, msg):
        if id == 1001:
            bc = c4d.BaseContainer()
            bc.SetId(c4d.BFM_ACTION)
            bc.SetInt32(c4d.BFM_ACTION_ID, ACTION_ID)
            self.SendParentMessage(bc)
        return True

class MainDialog(c4d.gui.GeDialog):
    subDialog = SubDialog()

    def CreateLayout(self):
        self.SetTitle('Main Dialog')
        self.AddButton(1000, 0, name="Open Sub-Dialog")
        # Adds a Gadget that will host a SubDialog
        #self.AddSubDialog(GADGET_ID_SUBDIALOG, c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, 100, 100)

        # Attaches the stored SubDialog to the Gadget previously created
        #self.AttachSubDialog(self.subDialog, GADGET_ID_SUBDIALOG)
        return True

    def Message(self, msg, result):
        if msg.GetId() == ACTION_ID:
            print "YES"
            return True
        return c4d.gui.GeDialog.Message(self, msg, result)

    def Command(self, param, bc):
        print bc
        if param == 1000:
            self.subDialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, subid=1)
        return True

    def Restore(self, pluginid, secref):
        if secref['subid'] == 1:
            return self.subDialog.Restore(pluginid, secref)
        else:
            return super(MainDialog, self).Restore(pluginid, secref)

class Command(c4d.plugins.CommandData):

    def Register(self):
        return c4d.plugins.RegisterCommandPlugin(
                PLUGIN_ID, "Sub-Dialog Message", 0, None, "", self)

    @property
    def dialog(self):
        if not hasattr(self, '_dialog'):
            self._dialog = MainDialog()
        return self._dialog

    def Execute(self, doc):
        return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID)

    def RestoreLayout(self, secref):
        return self.dialog.Restore(PLUGIN_ID, secref)

if __name__ == '__main__':
    Command().Register()

Did you try my example which exactly demonstrate the use of a SubDialog?
SubDialog is about having a dialog embedded into another one.

If you want to make communicate two independent GeDialog you have to use CoreMessage because there is no hierarchy between them they are both independent windows.

@m_adam Hi Maxime, I did try your example and I saw it working as a gadget but, you're right, I want to communicate between two GeDialogs. I followed your advice on using CoreMessage and found success with SpecialEventAdd. Thank you!