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.