Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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

    Add button to run a script

    Cinema 4D SDK
    3
    12
    2.1k
    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.
    • S
      stereo_stan
      last edited by

      Thank you. Yes, the goal is to be able to execute multiple commands in one plugin so I was trying to find a way to connect the GeDialog with some commands.

      I am new to programming and I have read through the GeDialog documentation and I can not figure out a way to connect the two concepts.

      Is there some example code that creates a few buttons that run some commands?

      Thank you for your help, I appreciate it.

      ferdinandF CairynC 2 Replies Last reply Reply Quote 0
      • ferdinandF
        ferdinand @stereo_stan
        last edited by ferdinand

        Hello @stereo_stan,

        thank you for reaching out to us. I am not one hundred percent sure how your question is meant.

        Scripts in the Python Scripting Manger in Cinema 4D can have their own button out of the box, you can even define the icon of that button. For details, please refer to the Icon section the Script Manger User Manual.

        In case your question was more about execution, @Cairyn already gave you most of the info (thanks!). In principle you would do this with a CommandData or a NodeData plugin, depending on what you have in mind exactly. Define there a STRING element in their interface definition and flag it as being MULTISTRING and Python. Also add a button to the interface. Then, in your implementation, listen for the button being clicked and load the Python code from the code window you did create. You could of course also add logic to populate that code window from a file or cut out the code window altogether and always execute files. Executing arbitrary modules is more a Python than a Python SDK question and therefore out of scope of support, but I have shown it here. There are multiple libraries in the standard Python library you can use for this, runpy is the least complicated of them.

        Cheers,
        ferdinand

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • CairynC
          Cairyn @stereo_stan
          last edited by

          @stereo_stan I suppose you don't mean to run an external script (Python allows this through Execute and Evaluate functions) since you're a beginner. You just want to call a functionality from your script (the same). So, you just need the dialog.

          The Github example (you found these, yes?) Memory Viewer contains a dialog that is called as part of the CommandData plugin. Let me quote this partially here (as it is (C)Maxon stuff anyway 😉 )

          class MemoryViewerCommandData(c4d.plugins.CommandData):
              """
              Command Data class that holds the MemoryViewerDialog instance.
              """
              dialog = None
          
              def Execute(self, doc):
                  """
                  Called when the user Execute the command (CallCommand or a clicks on the Command from the plugin menu)
                  :param doc: the current active document
                  :type doc: c4d.documents.BaseDocument
                  :return: True if the command success
                  """
                  # Creates the dialog if its not already exists
                  if self.dialog is None:
                      self.dialog = MemoryViewerDialog()
          
                  # Opens the dialog
                  return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaulth=400, defaultw=400)
          
              def RestoreLayout(self, sec_ref):
                  """
                  Used to restore an asynchronous dialog that has been placed in the users layout.
                  :param sec_ref: The data that needs to be passed to the dlg (almost no use of it).
                  :type sec_ref: PyCObject
                  :return: True if the restore success
                  """
                  # Creates the dialog if its not already exists
                  if self.dialog is None:
                      self.dialog = MemoryViewerDialog()
          
                  # Restores the layout
                  return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
          

          This CommandData is relatively simple, it just opens your dialog. Noteworthy are that you need to open the dialog as DLG_TYPE_ASYNC, which will allow you to work in C4D while the dialog is open; and the implementation of a RestoreLayout function which C4D uses to open a dialog that is embedded in the layout.

          The example also contains the MemoryViewerDialog class which is used in this CommandData, but you may not want to study that as it shows a number of different techniques (like GeUserArea) that you don't want yet, so I don't quote it. However, I saw in your other thread that you can construct a dialog class already, so I guess you do not need further pointers.

          To get a button into your dialog, use AddButton in your dialog's CreateLayout method as often as you like, like that:
          self.AddButton(ID_BUTTON3, c4d.BFH_SCALEFIT, name="Jump into code")
          then evaluate the commands from that button in the dialog's Command method

              def Command(self, id, msg):
                  if id==ID_BUTTON3:
                      print ("Button clicked")
                  return True
          
          1 Reply Last reply Reply Quote 0
          • S
            stereo_stan
            last edited by stereo_stan

            Thank you Cairyn and Ferdinand, this is all very helpful and I have a better understanding of different ways to approach this type of project.

            Yes, I do not think I want to run an external script, just have one script that a user can perform a few different commands from. Essentially so they can just have one command icon ( script ) in their interface and when they click on that it opens up a GeDialog with a bunch of options they can run by clicking on buttons inside of the GeDialog vs having to click on a bunch of different scripts. I assume those buttons are essentially other scripts that are all bundled together that they would drop in their scripts folder.

            I am so excited about all of the possibilities of adding programming into my daily work as a c4d animator-it is challenging to learn from a non-programming background but this forum has helped a lot.

            Thanks again.

            ferdinandF 1 Reply Last reply Reply Quote 0
            • ferdinandF
              ferdinand @stereo_stan
              last edited by

              Hello @stereo_stan

              unless I am overlooking something here, you can then simply drag and drop the script into one of Cinema's palettes as described in my previous posting. No extra steps required.

              Cheers,
              Ferdinand

              MAXON SDK Specialist
              developers.maxon.net

              1 Reply Last reply Reply Quote 0
              • S
                stereo_stan
                last edited by ferdinand

                One more question on this topic. I have tried to combine Cairyn's note on creating a button with the py-commanddata_dialogr13 script from Maxon github to create an async dialog.

                For some reason, it will not add my button to the dialog-basically just trying to add buttons to the py-commanddata script. Do you have any possible suggestions on making something like this work? Basically would like an async dialog with buttons. Thank you for any advice.

                """
                Copyright: MAXON Computer GmbH
                Author: Maxime Adam
                
                Description:
                    - Creates a Dialog which display 2 buttons OK and Cancel.
                
                Class/method highlighted:
                    - c4d.plugins.CommandData
                    - CommandData.Execute()
                    - c4d.gui.GeDialog
                    - GeDialog.CreateLayout()
                    - GeDialog.Command()
                """
                import c4d
                from c4d import gui
                
                
                # Be sure to use a unique ID obtained from www.plugincafe.com
                PLUGIN_ID = 1057171
                
                
                
                class ExampleDialog(c4d.gui.GeDialog):
                
                    def CreateLayout(self):
                        """This Method is called automatically when Cinema 4D Create the Layout (display) of the Dialog."""
                        # Defines the title of the Dialog
                        self.SetTitle("This is an example Dialog")
                
                        # Creates a Ok and Cancel Button
                        self.AddDlgGroup(c4d.DLG_OK | c4d.DLG_CANCEL)
                
                        
                
                        return True
                
                    def Command(self, messageId, bc):
                        """This Method is called automatically when the user clicks on a gadget and/or changes its value this function will be called.
                        It is also called when a string menu item is selected.
                
                        self.AddButton(ID_BUTTON3, c4d.BFH_SCALEFIT, name="Jump into code")
                
                        Args:
                            messageId (int): The ID of the gadget that triggered the event.
                            bc (c4d.BaseContainer): The original message container.
                
                        Returns:
                            bool: False if there was an error, otherwise True.
                        """
                        # User click on Ok buttonG
                        if messageId == c4d.DLG_OK:
                            print("User Click on yep")
                            return True
                
                        if ID == ID_BUTTON3:
                            print ("Button clicked")
                            return True    
                
                        # User click on Cancel button
                        elif messageId == c4d.DLG_CANCEL:
                            print("User Click on Cancel")
                
                            # Close the Dialog
                            self.Close()
                            return True
                
                        return True
                
                    def Command(self, id, msg):
                        if id == ID_BUTTON3:
                            print ("Button clicked")
                            return True    
                
                
                class ExampleDialogCommand(c4d.plugins.CommandData):
                    """Command Data class that holds the ExampleDialog instance."""
                    dialog = None
                    
                    def Execute(self, doc):
                        """Called when the user executes a command via either CallCommand() or a click on the Command from the extension menu.
                
                        Args:
                            doc (c4d.documents.BaseDocument): The current active document.
                
                        Returns:
                            bool: True if the command success.
                        """
                        # Creates the dialog if its not already exists
                        if self.dialog is None:
                            self.dialog = ExampleDialog()
                
                        # Opens the dialog
                        return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=400, defaulth=32)
                
                    def RestoreLayout(self, sec_ref):
                        """Used to restore an asynchronous dialog that has been placed in the users layout.
                
                        Args:
                            sec_ref (PyCObject): The data that needs to be passed to the dialog.
                
                        Returns:
                            bool: True if the restore success
                        """
                        # Creates the dialog if its not already exists
                        if self.dialog is None:
                            self.dialog = ExampleDialog()
                
                        # Restores the layout
                        return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
                
                
                # main
                if __name__ == "__main__":
                    # Registers the plugin
                    c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                                      str="Py-CommandData Dialog",
                                                      info=0,
                                                      help="Display a basic GUI",
                                                      dat=ExampleDialogCommand(),
                                                      icon=None)
                
                
                ferdinandF CairynC 2 Replies Last reply Reply Quote 0
                • ferdinandF
                  ferdinand @stereo_stan
                  last edited by ferdinand

                  Heelo @stereo_stan,

                  @stereo_stan said in Add button to run a script:

                  or some reason, it will not add my button to the dialog-basically just trying to add buttons to the py-commanddata script.

                  The posted code does not add any button. This would have to happen in ExampleDialog.CreateLayout() which does only set the title of the dialog and adds a cancle group. Is that what you mean with "button"?

                  Cheers,
                  Ferdinand

                  MAXON SDK Specialist
                  developers.maxon.net

                  1 Reply Last reply Reply Quote 0
                  • CairynC
                    Cairyn @stereo_stan
                    last edited by

                    @stereo_stan

                    As Ferdinand already said, you forgot to add the AddButton call, or rather (as I can see my line self.AddButton(ID_BUTTON3, c4d.BFH_SCALEFIT, name="Jump into code") in the script), you inserted it in the wrong place (it's now inside a comment section, where it doesn't do anything, and also in the wrong method.

                    Additionally, I need to tell you that you must define ID_BUTTON3 somewhere, or it will raise an error. And the snippet if ID == ID_BUTTON3: will not work since the parameter ID that I used is actually called messageId in your command method. Oops, and you duplicated the whole command method so now you have two of them and Python will only consider the latter and ignore the first.

                    Okay, I guess Maxon hates me for self promoting here, but this is not so much an API question now but a matter of plain Python understanding, so you may perhaps consider my Python/C4D API course under
                    https://www.patreon.com/cairyn
                    In section 10 I have multiple examples for dialog setup with layout, buttons, command method, text fields, radio buttons, separators, columns, etc.; too much to replicate here.

                    I have corrected the script for you a final time, removing all the comments and reducing the sample to the most necessary stuff:

                    import c4d
                    from c4d import gui
                    
                    PLUGIN_ID = 1057171
                    ID_BUTTON3 = 1001
                    
                    class ExampleDialog(c4d.gui.GeDialog):
                    
                        def CreateLayout(self):
                            self.SetTitle("This is an example Dialog")
                            self.AddButton(ID_BUTTON3, c4d.BFH_SCALEFIT, name="Jump into code")
                            self.AddDlgGroup(c4d.DLG_OK | c4d.DLG_CANCEL)
                            return True
                    
                        def Command(self, messageId, bc):
                            if messageId == c4d.DLG_OK:
                                print("User Click on yep")
                                return True
                    
                            elif messageId == ID_BUTTON3:
                                print ("Button clicked")
                                return True    
                    
                            elif messageId == c4d.DLG_CANCEL:
                                print("User Click on Cancel")
                                self.Close()
                                return True
                    
                            return True
                    
                    class ExampleDialogCommand(c4d.plugins.CommandData):
                        dialog = None
                        
                        def Execute(self, doc):
                            if self.dialog is None:
                                self.dialog = ExampleDialog()
                            return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaultw=400, defaulth=32)
                    
                        def RestoreLayout(self, sec_ref):
                            if self.dialog is None:
                                self.dialog = ExampleDialog()
                    
                            return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
                    
                    if __name__ == "__main__":
                        c4d.plugins.RegisterCommandPlugin(id=PLUGIN_ID,
                                                          str="Py-CommandData Dialog",
                                                          info=0,
                                                          help="Display a basic GUI",
                                                          dat=ExampleDialogCommand(),
                                                          icon=None)
                    

                    827c6608-acfc-4a41-b73c-a3348488d297-image.png

                    1 Reply Last reply Reply Quote 1
                    • S
                      stereo_stan
                      last edited by

                      Thank you Cairyn and Ferdinand again. This is all making much more sense now, I appreciate you helping me understand how to correctly set up a simple interface. I do need to spend more time just learning the fundamentals of Python.

                      1 Reply Last reply Reply Quote 0
                      • ferdinandF
                        ferdinand
                        last edited by

                        Hello @stereo_stan,

                        without further questions or replies, we will consider this topic as solved by Monday, the 30th and flag it accordingly.

                        Thank you for your understanding,
                        Ferdinand

                        MAXON SDK Specialist
                        developers.maxon.net

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