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.
    • CairynC
      Cairyn
      last edited by

      I am actually not sure what you mean by

      with a button click instead of just clicking on the script

      A Command Plugin is essentially one command that is triggered by clicking the plugin, as the name says. If you want to embed a button in your GUI, you can just drag and drop the icon (I see that you have one) in any toolbar you like.

      You can of course load a dialog instead of directly executing the command. In that case you need to derive a new dialog from the class GeDialog and open the dialog asynchronously (see the other threads recently), then you can do tricks with it like embedding it into the layout and have C4D open it automatically on start. However, this makes only sense if you have more than one functionality to execute, or input fields for the user to enter data in, otherwise you end up with just one button in the dialog, which is a bit wasteful.

      Also, isn't that what you just asked in the other thread, where you already have a GeDialog created?

      1 Reply Last reply Reply Quote 0
      • 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