1

What's the difference for the two methods of UI initiator?

I’m building a UI with a sub-dialog and need it to appear only when a user clicks a button. However, I’m encountering different behaviors with two different approaches.

Method 1: Delayed Creation (Works as Expected)

In this method, I create and show the sub-dialog only when the button is clicked:

Class MySub:UIFrame
{
    Object Init(Object self)
    {
        TagGroup DLGitems = DLGCreateDialog("Sub")
        TagGroup RadioList=DLGCreateRadioList()
        RadioList.DLGAddRadioItem("option 1",1)
        RadioList.DLGAddRadioItem("option 2",2)
        RadioList.DLGAddRadioItem("option 3",3)
        DLGitems.DLGAddElement(RadioList)
        Return self.super.Init(DLGitems)
    }
}
Class MyMain:UIFrame
    {
    Object SubDialog
    Void CallSubDialog(Object self)
        {
        Result("\nOpen sub-dialog.")
        SubDialog.Pose()                                // call the local object
        self.LookUpElement("Label").DLGTitle("option chosen")
        }
    Object Init(Object self, Object SDpass) 
        {
        SubDialog = SDpass                              // Keep the object in a local variabl
        TagGroup DLGitems = DLGCreateDialog("Main")
        DLGitems.DLGAddElement(DLGCreateLabel("choose option").DLGIdentifier("Label"))
        DLGitems.DLGAddElement(DLGCreatePushButton("Options","CallSubDialog"))
        Return self.super.Init(DLGitems)
        }
    }
Object SubDialogOBJ = Alloc(MySub).Init()               // Initialize the sub-dialog object in the main script
Object DialogOBJ = Alloc(MyMain).Init(SubDialogOBJ)     // Pass on the object into the other
DialogOBJ.Display("Dialog")

Method 2: Immediate Creation in the Constructor (Unexpected Behavior)

Here, I initialize and show the sub-dialog in the constructor, which causes the sub-dialog to display as soon as the script runs:

Class MySub:UIFrame
{
    TagGroup gen_MySubUI_dlg(Object self)
    {
        TagGroup DLGitems = DLGCreateDialog("Sub")
        TagGroup RadioList=DLGCreateRadioList()
        RadioList.DLGAddRadioItem("option 1",1)
        RadioList.DLGAddRadioItem("option 2",2)
        RadioList.DLGAddRadioItem("option 3",3)
        DLGitems.DLGAddElement(RadioList)
        Return DLGitems
    }
    MySub(Object self)
    {
        self.init(self.gen_MySubUI_dlg())
        self.Display("MySubUI")
    }
    ~MySub(Object self)
    {
        Result("Quit" + "\n")
    }

}
Class MyMain:UIFrame
    {
    Object SubDialog
    Void CallSubDialog(Object self)
        {
        Result("\nOpen sub-dialog.")
        SubDialog.Pose()                                // call the local object
        self.LookUpElement("Label").DLGTitle("option chosen")
        }
    Object Init(Object self, Object SDpass) 
        {
        SubDialog = SDpass                              // Keep the object in a local variabl
        TagGroup DLGitems = DLGCreateDialog("Main")
        DLGitems.DLGAddElement(DLGCreateLabel("choose option").DLGIdentifier("Label"))
        DLGitems.DLGAddElement(DLGCreatePushButton("Options","CallSubDialog"))
        Return self.super.Init(DLGitems)
        }
    }
Object SubDialogOBJ = Alloc(MySub)              // Initialize the sub-dialog object in the main script
Object DialogOBJ = Alloc(MyMain).Init(SubDialogOBJ)     // Pass on the object into the other
DialogOBJ.Display("Dialog")

Questions:

Primary Question:

  • Why do these two methods behave differently? Specifically, why does the sub-dialog in Method 2 appear immediately upon running the script instead of waiting for the button click?

Additional Question:

  • When running a third example (not included here), I receive the following error message:
Class MySub:UIFrame
{
    TagGroup gen_MySubUI_dlg(Object self)
    {
        TagGroup DLGitems = DLGCreateDialog("Sub")
        TagGroup RadioList=DLGCreateRadioList()
        RadioList.DLGAddRadioItem("option 1",1)
        RadioList.DLGAddRadioItem("option 2",2)
        RadioList.DLGAddRadioItem("option 3",3)
        DLGitems.DLGAddElement(RadioList)
        Return DLGitems
    }
    MySub(Object self)
    {
        self.init(self.gen_MySubUI_dlg())
        self.Display("MySubUI")
    }
    ~MySub(Object self)
    {
        Result("Quit" + "\n")
    }

}
Class MyMain:UIFrame
    {
    Object SubDialog
    Void CallSubDialog(Object self)
        {
        Result("\nOpen sub-dialog.")
        Alloc(MySub)                                // call the local object
        }
    Object Init(Object self) 
        {                           // Keep the object in a local variabl
        TagGroup DLGitems = DLGCreateDialog("Main")
        DLGitems.DLGAddElement(DLGCreateLabel("choose option").DLGIdentifier("Label"))
        DLGitems.DLGAddElement(DLGCreatePushButton("Options","CallSubDialog"))
        Return self.super.Init(DLGitems)
        }
    }

Object DialogOBJ = Alloc(MyMain).Init()     // Pass on the object into the other
DialogOBJ.Display("Dialog")

What I’ve Tried:

  • Verified that the button click event is correctly connected in Method 1, which behaves as expected.
  • Reviewed the sub-dialog’s constructor and display logic without finding any obvious issues.

Any insights into the differences in these initialization methods and help identifying the error in the third example would be greatly appreciated.

1 Answer 1

1

I do not quite understand your question. In your 2nd code you call self.Display in the constructor, so naturally the dialog gets immediately displayed?

Maybe you need to understand the concept of a constructor method better? This method is called (i.e. the code is run) the moment the object is created in memory, i.e. when you call Alloc(mySub) you create the object of class 'mySub' in memory, which invokes its constructor method.


I'm adding an example of what you might want to do: Allocate the sub-dialog while the main script is still in scope, but do not display it. Instead, hold it as member variable of the the main dialog and display when the button is pressed (in the "OnButtonPressed" action method).

There are different ways that could be done:

  1. Allocated on the main thread and pass the object as parameter to the main-dialog (on the main script) as in:
// On the main script:
object sub = Alloc(sub)
object main = Alloc(main)
main.SetSubDlg(sub)   // SetSubDlg is a custom method that stores into a member variable
main.LaunchDisplay()  // LaunchDisplay is a custom method that shows the main dialog.
  1. Allocate the sub-dialog in the constructor of the main dialog object. As the main dialog is allocated by the call on the main script, its constructor is immediately called while the script code is still in scope. I prefer this way, as it is cleaner encapsulating everything.
class CSubDialog : UIframe
{
    number CreateAndPose(object self)
    {
        TagGroup dlg,dlgitems
        dlg = DLGCreateDialog("SubDialog",dlgitems)
        dlgItems.DLGAddElement(DLGCreateLabel("I'm the sub dialog."))
        return self.init(dlg).pose()
    }
}

class CMainDialog : UIframe
{
    object subDlg
    CMainDialog(object self)
    {
        // The constructor of CMainDialg is called as soon as the 
        // Alloc(CMainDialog) in the main program is called.
        // At this time, the whole script code is still in scope
        // so the subDLG can be allocated. Just hold it as member
        // of this dialog.
        subDlg = Alloc(CSubDialog)
    }
    
    void OnLaunchSub(object self)
    {
        // Safer coding: Check that the member variable is 
        // holding a valid object. 
        if ( !subDlg.ScriptObjectIsValid() ) throw( "No Sub dialog found." )
        // Further safety, check if is of the correct class (All lower case!)
        if ("csubdialog" != subDLG.ScriptObjectGetClassName()) throw( "Wrong object." )
        subDLG.CreateAndPose()      
    }
    
    object CreateAndDisplay(object self)
    {
        TagGroup dlg,dlgitems
        dlg = DLGCreateDialog("Main Dialog",dlgitems)
        dlgItems.DLGAddElement(DLGCreateLabel("I'm the main dialog."))
        dlgItems.DLGAddElement(DLGCreatePushButton("Launch","OnLaunchSub"))
        self.init(dlg).display("Main Dialog")
        return self
    }
    
}

Alloc(CMainDialog).CreateAndDisplay()
Sign up to request clarification or add additional context in comments.

3 Comments

I see. But if I changed it to the 3rd code, in which I put Alloc(MySub) into CallSubDialog function, it will show error "Cant find MySub".
Your third example code nicely illustrates the fact that a class definition is only valid during the life of the script (or of any object of that class created during script execution). Since your third example does not explicitly allocate an instance of MySub during its execution (unlike your first example), that class definition is gone by the time you launch your sub-dialog by clicking the button in the MyMain dialog. As indicated in the on-line help on Objects, one solution in this case is to install the class definition portion of your script as a library.
@ChenZX. As Mike pointed out. The alternative approach is to perform the Alloc() in the Constructor of the main object, but the SubDialog display not in the contstructor of the SubDialog, but explicitly as a call in the MainDialog's "OnButtonPressed". I'll add an example to my post...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.