Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    How to return info from a modal dialog ?

    Scheduled Pinned Locked Moved PYTHON Development
    9 Posts 0 Posters 954 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H Offline
      Helper
      last edited by

      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

      1 Reply Last reply Reply Quote 0
      • H Offline
        Helper
        last edited by

        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()
        
        1 Reply Last reply Reply Quote 0
        • H Offline
          Helper
          last edited by

          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

          1 Reply Last reply Reply Quote 0
          • H Offline
            Helper
            last edited by

            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

            1 Reply Last reply Reply Quote 0
            • H Offline
              Helper
              last edited by

              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 ?

              1 Reply Last reply Reply Quote 0
              • H Offline
                Helper
                last edited by

                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

                1 Reply Last reply Reply Quote 0
                • H Offline
                  Helper
                  last edited by

                  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

                  1 Reply Last reply Reply Quote 0
                  • H Offline
                    Helper
                    last edited by

                    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

                    1 Reply Last reply Reply Quote 0
                    • H Offline
                      Helper
                      last edited by

                      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.

                      1 Reply Last reply Reply Quote 0
                      • First post
                        Last post