How to return info from a modal dialog ?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 02:31, xxxxxxxx wrote:

    Hi there, I have created a modal dialog and opened it OK.
    I know how to use the Command() function to execute code when a gadget is pressed.
    But I can't work out how to get information out of the dialogue to use in my CommandData plugin.
    Specifically, I need to know what checkboxes the user left checked while in the modal dialog. Now I know the command for this is GetBool(id) and it works inside the Command() function. But Command() doesn't seem to allow any return apart from True/ False.
    And if I use GetBool(id) on the instance of MyDialog in the CommandData
    plugin, it always returns False, I guess because by then the dialogue is closed.
    I can get the information out from inside the Command() function by writing to a global variable from inside the function, but I understand this is a very bad way to do it ?
    So I need help to know how to return information from a modal dialog.
    Here is a stripped down, minimal example of my code :

    class MyDialog(gui.GeDialog) :

    def CreateLayout(self) :
            self.SetTitle("My Dialog")
            self.AddCheckbox(10001, c4d.BFH_LEFT,
                             initw = 85, inith = 10, name = "Checkbox")

    self.GroupBegin(OK_GROUP, c4d.BFH_CENTER,
                            cols = 2, title = "OK/ Cancel")

    self.GroupBorderSpace(5,5,5,5)

    self.AddButton(10002, c4d.BFH_LEFT,
                             initw = 100, inith = 15, name = "OK")

    self.AddButton(10003, c4d.BFH_RIGHT,
                             initw = 100, inith = 15, name="Cancel")

    self.GroupEnd()
            return True

    def Command(self, id, msg) :
            if id == 10001:
                 pass
            if id == 10002:
                 self.Close()
            if id == 10002:
                 self.Close()
            return True

    class MyCommandData(plugins.CommandData) :
        def Execute(self, doc) :
            dialog = MyDialog()
            dialog.Open(c4d.DLG_TYPE_MODAL, PLUGIN_ID)
            return True



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 03:03, xxxxxxxx wrote:

    Just give your dialog a function that returns the result, for instance:

    """  
    Modal Dialog with Result - Example for decade on plugincafe.com  
    licensed under WTFPL.  
    """  
      
    import  c4d  
    from    c4d.gui     import GeDialog  
      
    class MyModal(GeDialog) :  
      ID_TEXT             = 10002  
      ID_BUTTON_OK        = 10021  
      ID_BUTTON_CANCEL    = 10022  
      # symbolscache is not initialised on startup, create FULLFIT later  
      FULLFIT             = None  
      
      def __init__(self, text, okButtonTitle = "OK", cancelButtonTitle = "Cancel") :  
          self.FULLFIT        = c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT  
          self.__text         = text  
          self.__result       = self.ID_BUTTON_CANCEL  
          self.__okbtn        = okButtonTitle  
          self.__cncbtn       = cancelButtonTitle  
      
      def CreateLayout(self) :  
          self.AddStaticText(self.ID_TEXT, c4d.BFH_CENTER | c4d.BFV_CENTER, 0, 0, self.__text)  
      
          self.GroupBegin(1000, self.FULLFIT, cols = 2)  
          self.AddButton(self.ID_BUTTON_OK, self.FULLFIT, 50, 15, name = self.__okbtn)  
          self.AddButton(self.ID_BUTTON_CANCEL, self.FULLFIT, 50, 15, name = self.__cncbtn)  
          self.GroupEnd()  
      
          return True  
      
      def Command(self, id, msg) :  
          if id == self.ID_BUTTON_OK:  
              self.__result   = self.ID_BUTTON_OK  
              self.Close()  
          elif id == self.ID_BUTTON_CANCEL:  
              self.__result   = self.ID_BUTTON_CANCEL  
              self.Close()  
      
          return True  
      
      def Open(self) :  
          GeDialog.Open(self, c4d.DLG_TYPE_MODAL)  
      
      @ property  
      def result(self) :  
          return self.__result  
      
    def main() :  
      dlg = MyModal("Do you really want to quit ?", "Yes", "No")  
      dlg.Open()  
      print dlg.result  
      
    if __name__ == "__main__":  
      main()
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 09:22, xxxxxxxx wrote:

    Nux.
    Is there a reason why you keep using this format: __function__ throughout your code?

    Most of the time they aren't required. And the code can be written neater like this:

    import c4d  
    from c4d import gui  
      
    GROUP1 =1000   #GROUP1  id  
    TEXTBOX=1001   #TEXTBOX id  
    BUTTON1=1002   #BUTTON1 id  
    BUTTON2=1003   #BUTTON2 id  
      
    class ExampleDlg(gui.GeDialog) :   
      
      def CreateLayout(self) :  
        #creat the layout of the dialog  
        self.SetTitle("Simple Dialog")  
        self.GroupBegin(GROUP1, c4d.BFH_SCALEFIT, 3, 1)  
        self.AddEditText(TEXTBOX, c4d.BFH_SCALEFIT)  
        self.AddButton(BUTTON1, c4d.BFH_SCALE, name="MessadeDialog")  
        self.AddButton(BUTTON2, c4d.BFH_SCALE, name="Close")  
        self.GroupEnd()  
        return True  
      
      def InitValues(self) :  
        #initiate the gadgets with values  
        self.SetString(TEXTBOX, "Hello World!")  
        return True  
      
      def Command(self, id, msg) :   
        #handles what happens when GUI objects are clicked   
        if id==BUTTON1:  
         gui.MessageDialog(self.GetString(TEXTBOX))  
         self.SetString(TEXTBOX, "Button was used")         
        elif id==BUTTON2:  
           print "You closed the dialog"  
           self.Close()  
        return True  
      
    dlg = ExampleDlg()  
    dlg.Open(c4d.DLG_TYPE_MODAL, defaultw=300, defaulth=50)
    

    Is there some benefit to using all of those __whatever__ throught the code?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 11:21, xxxxxxxx wrote:

    Yes, there is. It makes the variables private (Well, not *really* but almost).
    But the format is not __variable__. it is __variable. The first is not private.
    Sometimes you really don't want that the user can't modify the variables without using a function for it.
    I often post examples with some extra stuff some may didn't know so they get some extra information on the fly.

    GROUP1 =1000   #GROUP1  id   
    TEXTBOX=1001   #TEXTBOX id   
    BUTTON1=1002   #BUTTON1 id   
    BUTTON2=1003   #BUTTON2 id
    

    Do not use global variables. They are unnecessery as well as it makes really sense in this case to make them static variables for the dialog class.

    And, most important: Your dialog does not give any result after the dialog was closed. ;-)

    Cheers,
    Niklas



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 11:36, xxxxxxxx wrote:

    Thanks Nux, works a treat & allows me to progress with my plugin.
    But if you don't mind I have a couple of questions because I don't understand HOW it works.
    I don't understand the def __init__, it's not listed as a method under c4d.giu.GeDialog. I've come across it before elsewhere but normally you don't have to handle it at all.
    It seems you're creating variables there that are global to the MyModal class ie they can be accessed from inside any of the def in the class. I don't understand why you need to do that rather than list them with your ID constants, right under the class. But I tried it that way and it does seem it doesn't work, you can't update variables you define there.
    And what does the double underscore __ signify ?.
    Thanks for your help

    Edit, cross posted with scott asking some of the same questions.
    Also, isn't it OK to leave my constants global ? becuase I want to access them from both the dialog class and the CommandData class, and unnlike my example, my real plugin has a lot of them. I have a python book (not c4d, just python)that says global constants are ok but variables are discouraged ?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 03/07/2011 at 12:14, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Your dialog does not give any result after the dialog was closed. ;-)

    Sure it does.
    It prints to the console. The same way your code prints to the console when the close function is called.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/07/2011 at 03:34, xxxxxxxx wrote:

    @Scott: Yea, it prints to the console. But this is not what decade wanted to do.
    He wanted get some data after the dialog was closed.

    @decade:

    Originally posted by xxxxxxxx

    I don't understand the def __init__,

    This is a special method, the Class-constructor. There are more special methods like __del__, __add__, __invert__, __iter__, etc.
    See more about it here: link

    Originally posted by xxxxxxxx

    becuase I want to access them from both the dialog class and the CommandData class,

    This has good reason.
    Why should I use global variable if I can avoid them ?
    You can access those ID:

    if dlg.result == MyModal.ID_BUTTON_OK:  
      pass # . . .
    
    if dlg.result == dlg.ID_BUTTON_OK:  
      pass # . . .
    

    I do never create IDs in the global scope. even I'm using a Dialog created with ResEdit. Instead I create a "foo"-class that holds my ID's. This keeps the global - dictionary smaller. 😉

    class foo:  
      """ Holds some ID's. """  
    res   = foo()  
    res.EDT_STATIC_TEXT = 10012  
    # etc ...
    

    If you like the dictionary style the more but you still want to access those IDs via Pointnotation, you can also do this:

    class foo:  
      """ Holds some ID's. """  
    res    = foo()  
    res.__dict__ = {  
      "EDT_STATIC_TEXT":   10012,  
      # etc ...  
    }  
    print res.EDT_STATIC_TEXT
    

    I do also never never ever Register my Plugin globally.
    1. This is again in global scope
    2. It is much more clear code

    class MyObjectData(ObjectData) :  
      PLUGIN_ID        = 1002136  
      ICON             = None     # We use this as a class - variable to be able to access to it in the plugin, you may need this ?  
      # ...  
      @ staticmethod  
      def Register(cls) :  
          iconPath = join(dirname(__file__), "res", "icon.tif")  
          icon     = BaseBitmap()  
          icon.InitWith(iconPath)  
      
          data     = {  
              "id":          cls.PLUGIN_ID,  
              "str":         "My Object data Plugin",  
              "info":        c4d.OBJECT_MODIFIER,  
              "icon":        icon,  
              "description": "Omyobject",  
              "g":           cls,  
          }  
      
          if not RegisterObjectPlugin( ** data ) :  
              print "Failed registering Object Plugin"  
              return False  
          else:  
              cls.ICON = icon  
              return True  
      
    # ...  
    def main() :  
      MyObjectData.Register()  
      
    if __name__ == "__main__":  
      main()
    

    Originally posted by xxxxxxxx

    global constants are ok but variables are discouraged ?

    Yea, if you don't want modify the, it's ok, but still not the best way to do.
    Accessing global variables is always slower than accessing local ones.
    The more outter the variables are, the more time it takes to access them.

    Cheers,
    Niklas



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/07/2011 at 08:18, xxxxxxxx wrote:

    The reason most people are using globals is because we were taught that way. Even by the most experienced C4D coders.
    I once asked about whether using globals was a bad thing on CGTalk. And the answer I got was that they aren't that bad for what we're using them for.
    And since I'm new at writing code. And these people were kind enough to help me. I didn't want to disagree with them. So I dropped it.

    Most of the time globals really aren't going to hurt you for what we're doing in C4D. And everybody seems to be using them. You won't see any noticeable speed differences either, because C4D isn't a game engine.
    But this is the problem with using the internet as a learning tool. And learning from other users.
    You often get taught how to cheat. Without them telling you that you're cheating. And then all of a sudden you find out one day that you've been doing it ......let's call it.... less than the most optimistic way.

    If I remember correctly.
    I think MAXON even uses globals in their Coffee SDK examples.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 04/07/2011 at 12:41, xxxxxxxx wrote:

    Big thanks for the explanations! I will probably take another pass at my code once the functionality is there and think about how to tidy up/ organise it best.


Log in to reply