dialogdm-script

How to correctly create sub-dialogs from within dialogs?


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:

Additional Question:

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:

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


Solution

  • 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()