Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to define a PREINIT or POSTINIT program in a dialogue box

    I have writing a dialogue box for a command called
    Code:
    reproot
    (see documentation for context). The only relevant context for this question is that this command requires a settings file and the dialogue box will help a user set up that file.

    Before opening the dialogue box, the command looks if the settings file exist, and if it does, it will prepopulate the dialogue box with that is already in the file. I have been able to generate the dialogue box, but I want to define a PREINIT or POSTINIT program has described in section 5.6 in this Stata manual: https://www.stata.com/manuals13/pdia...logprogramming. However, I have tried to defined it in all different ways I can imagine, but I always get a 198 error and I have not been able to find some more meaningful error message when running the command with tracing turned on.

    I know a reproducible example is almost always needed to give specific advice. But I am not sure how to best do so as without making it too complex. Happy to make an attempt if no one is able to point me to an example or other resource where I can see a general example of how this is done. For what it is worth, here is the current version of the dlg file, but I probably would have to give more context for the details to work: https://github.com/worldbank/repkit/...do/reproot.dlg. On line 84 I am trying to define the POSTINIT program. I am aware that the program is empty in that code, but I have tried with some basic code and I still get the same error. If I change
    Code:
    POSTINIT_PROGRAM test
    to
    Code:
    PROGRAM test
    but leave the program empty, I do not get a 198 error. But that might be different as a POSTINIT command is executed automatically.

    I have searched for other dlg files to see if I can find any example of POSTINI usage, but have not found any. So if anyone has an example like that I can look at to start with that might be the best option before I am trying to make a reproducible example.




  • #2
    Here is a minimal dialog that shows how to name these programs. I also include an example program that is associated with a tab.
    Code:
    VERSION 18.0
    
    INCLUDE _std_large
    
    INCLUDE header
    HELP hlp1, view(help contrast)
    RESET res1
    
    // preinit program called before any dialog controls are created
    PROGRAM PREINIT_PROGRAM
    BEGIN
        call main.ed_label.setvalue "preinit value"
    END
    
    // postinit program called once all dialog controls have been created
    PROGRAM POSTINIT_PROGRAM
    BEGIN
        call main.ed_label.setvalue "postinit value"
    END
    
    DIALOG main, title("Title") tabtitle("Main")
    BEGIN
        TEXT tx_label _lft _top _iwd ., label("text label:")
        EDIT ed_label @ _ms @ ., label("text label")
    END
    
    // postinit program called after opt tab controls have been created
    PROGRAM opt_POSTINIT_PROGRAM
    BEGIN
        call opt.ed_label.setvalue "option's postinit value"
    END
    
    DIALOG opt, tabtitle("Options")
    BEGIN
        TEXT tx_label _lft _top _iwd ., label("option label:")
        EDIT ed_label @ _ms @ ., label("option label")
    END

    Comment


    • #3
      Ah, thank you! I did not realize POSTINIT_PROGRAM should replace the PROGRAM name, I thought it would replace the command PROGRAM.

      May I ask a follow up question? Here is an excerpt of my dialogue box definition:

      Code:
      // Default search dept tab
      DIALOG searchpaths, label("reproot - Manage settings file") tabtitle("Search Paths")
      BEGIN
      
        // Default search dept tab
        GROUPBOX gb_sd_desc  10  10 450 50, label("Description:")
          TEXT   tx_sp_1     +10 +20 400 . , label("This sets the paths reproot will search for root files.")
      
        GROUPBOX gb_envpath      10 +35 450 190, label("Select the search paths to be included:")
          CHECKBOX ck_envpath1  +10 +20 450 ., label(r(envpath1_text)) nomemory default(r(envpath1_default))
          CHECKBOX ck_envpath2   @  +20 450 ., label(r(envpath2_text)) nomemory default(r(envpath2_default))
          CHECKBOX ck_envpath3   @  +20 450 ., label(r(envpath3_text)) nomemory default(r(envpath3_default))
          CHECKBOX ck_envpath4   @  +20 450 ., label(r(envpath4_text)) nomemory default(r(envpath4_default))
          CHECKBOX ck_envpath5   @  +20 450 ., label(r(envpath5_text)) nomemory default(r(envpath5_default))
          CHECKBOX ck_envpath6   @  +20 450 ., label(r(envpath6_text)) nomemory default(r(envpath6_default))
          CHECKBOX ck_envpath7   @  +20 450 ., label(r(envpath7_text)) nomemory default(r(envpath7_default))
          CHECKBOX ck_envpath8   @  +20 450 ., label(r(envpath8_text)) nomemory default(r(envpath8_default))
      
      
        TEXT    tx_searchpath 10 +40 200 ., label("Add another search path:")
        FILE    searchpath    @  +20 400 ., directory label("Browse . . . ") option(searchpath) nomemory
        TEXT    tx_sp_rd1     10 +20 200 ., label("Search depth specific to this search path (optional)")
        SPINNER sp_recdepth   @  +25 50  ., option(sp_rd) min(0) max(25) default(0) nomemory
        BUTTON  btn_envpath   @  +25 200 ., label("Add path to possible options")
      
      END
      
      PROGRAM POSTINIT_PROGRAM
      BEGIN
        call searchpaths.ck_envpath1.disable
        call searchpaths.ck_envpath8.disable
      END
      In this example the POSTINIT program runs correctly and disables the first and the last check box. However, I want the disabling to be conditional on the label being empty or not. In my test example, r(envpath1_text) is never missing and r(envpath8_text) is always missing. I want to disable checkboxes that does not have a label. I tried this:

      Code:
      PROGRAM POSTINIT_PROGRAM
      BEGIN
        if missing(searchpaths.ck_envpath1.label) {
          call gaction searchpaths.ck_envpath1.disable
        }
        if missing(searchpaths.ck_envpath8.label) {
          call gaction searchpaths.ck_envpath8.disable
        }
      END
      But this does not work as I intend it to. Eventually I will move this out to a separate program that POSTINIT_PROGRAM calls, as I want to run these disable checks after the BUTTON btn_envpat has been pressed and the labels on the checkboxes might have been modified.

      Comment


      • #4
        I don't think you can assign string values to the CHECKBOX control. Furthermore, its value should only be 0 (off) or 1 (on).

        For string-valued controls, like EDIT, VARLIST, FILE, LISTBOX, COMBOBOX, COLOR, and EXP controls, you can use the .iseq() and .isneq() functions.

        Here is an example dialog that pulls the format settings for coefficient tables into EDIT controls and initializes the checkboxes based on whether the settings are default (empty) or customized by the user. By default, we want the checkboxes off and the edit controls disabled, but if a format setting has a custom value we want the checkbox on and the edit field enabled. We accomplish this with program init_formats, which is called by POSTINIT_PROGRAM.
        Code:
        VERSION 18.0
        
        INCLUDE _std_large
        
        INCLUDE header
        HELP hlp1, view(help contrast)
        RESET res1
        
        PROGRAM POSTINIT_PROGRAM
        BEGIN
            // program init_formats can be used in other programs/scripts if
            // needed
            call program init_formats
        END
        
        PROGRAM init_formats
        BEGIN
            // enable the controls of coef table formats that have been -set-
        
            if main.ed_cformat.isneq("") {
                call main.ck_cformat.seton
                call main.ed_cformat.enable
            }
            if main.ed_cformat.iseq("") {
                call main.ck_cformat.setoff
                call main.ed_cformat.disable
            }
        
            if main.ed_pformat.isneq("") {
                call main.ck_pformat.seton
                call main.ed_pformat.enable
            }
            if main.ed_pformat.iseq("") {
                call main.ck_pformat.setoff
                call main.ed_pformat.disable
            }
        
            if main.ed_sformat.isneq("") {
                call main.ck_sformat.seton
                call main.ed_sformat.enable
            }
            if main.ed_sformat.iseq("") {
                call main.ck_sformat.setoff
                call main.ed_sformat.disable
            }
        END
        
        PROGRAM check_formats
        BEGIN
            // enable/disable format edit controls, depending on their
            // associated checkbox status
        
            if main.ck_cformat {
                call main.ed_cformat.enable
            }
            if !main.ck_cformat {
                call main.ed_cformat.disable
            }
        
            if main.ck_pformat {
                call main.ed_pformat.enable
            }
            if !main.ck_pformat {
                call main.ed_pformat.disable
            }
        
            if main.ck_sformat {
                call main.ed_sformat.enable
            }
            if !main.ck_sformat {
                call main.ed_sformat.disable
            }
        END
        
        DIALOG main, title("Title") tabtitle("Main")
        BEGIN
            CHECKBOX ck_cformat _lft _top _iwd ., ///
                onclickon(program check_formats) ///
                onclickoff(program check_formats) ///
                label("coefficient format:")
            EDIT ed_cformat @ _ms @ ., ///
                label("coefficient format") ///
                default(c(cformat)) nomemory
        
            CHECKBOX ck_pformat _lft _ls _iwd ., ///
                onclickon(program check_formats) ///
                onclickoff(program check_formats) ///
                label("p-value format:")
            EDIT ed_pformat @ _ms @ ., ///
                label("p-value format") ///
                default(c(pformat)) nomemory
        
            CHECKBOX ck_sformat _lft _ls _iwd ., ///
                onclickon(program check_formats) ///
                onclickoff(program check_formats) ///
                label("test statistic format:")
            EDIT ed_sformat @ _ms @ ., ///
                label("test statistic format") ///
                default(c(sformat)) nomemory
        END
        With the following coefficient table settings
        Code:
        * customize the coefficient format
        set cformat %9.2fc
        * ensure the p-value and test statistic formats are default
        set pformat
        set sformat
        here is a screenshot of the above dialog as it initially shows up on my Mac.

        Click image for larger version

Name:	Screenshot 2024-10-28 at 10.56.17 AM.png
Views:	1
Size:	25.6 KB
ID:	1766547

        Comment


        • #5
          Thank you so much Jeff. Sorry for slow reply, I only work part-time for this project and do not have time to come back to this very frequently. I got the POSTINIT program to work.

          I might be pushing my luck with your very helpful kindness but can I ask you one more question. Especially since my question is no longer under the topic of POSTINIT programs. Let me know if you would prefer for me to create a new post.

          My current issue is in the add_searchpath program below. I want to take the string value from the new_path FILE field in the dialogue box and add it to the one of the EDIT fields in that same dialogue box. Eventually, I will want to add the FILE value to the first empty EDIT field, but for now I am still struggling to add it to any EDIT field.

          The code example below shows different approaches I am trying. call searchpaths.ed_path6.setvalue "abc" was just as test to add a hard coded string. call searchpaths.ed_path7.setvalue searchpaths.new_path and call searchpaths.ed_path8.setvalue newreprootpath are both attempts of setting the EDIT fields to the value of new_path.

          However, in all these cases what comes after setvalue is treated as a hardcoded string and the three EDIT fields are populated literally abc, searchpaths.new_path and newreprootpath. But I want to use the current value of the field searchpaths.new_path.

          Code:
          // https://www.stata.com/manuals13/pdialogprogramming.pdf#pdialogprogramming
          // ----------------- set version number and define size of box ---------
          VERSION 14
          POSITION . . 600 500
          
          // ------------------------------------------- define a dialog ---------
          // Default search dept tab
          DIALOG searchpaths, title("reproot - settings file setup") tabtitle("Search Paths")
          BEGIN
          
            // Default search dept tab
            GROUPBOX gb_sd_desc  10  10 450 50, label("Description:")
              TEXT   tx_sp_1     +10 +20 400 . , label("This sets the paths reproot will search for root files.")
          
            GROUPBOX gb_envpath      10 +35 450 250, label("Select the search paths to be included:")
          
              CHECKBOX ck_path1 +10 +20 20 .
              EDIT ed_path1 +20 @ 400 ., default(r(envpath1_text)) nomemory
              CHECKBOX ck_path2 -20 +25 20 .
              EDIT ed_path2 +20 @ 400 ., default(r(envpath2_text)) nomemory
              CHECKBOX ck_path3 -20 +25 20 .
              EDIT ed_path3 +20 @ 400 ., default(r(envpath3_text)) nomemory
              CHECKBOX ck_path4 -20 +25 20 .
              EDIT ed_path4 +20 @ 400 ., default(r(envpath4_text)) nomemory
              CHECKBOX ck_path5 -20 +25 20 .
              EDIT ed_path5 +20 @ 400 ., default(r(envpath5_text)) nomemory
              CHECKBOX ck_path6 -20 +25 20 .
              EDIT ed_path6 +20 @ 400 ., default(r(envpath6_text)) nomemory
              CHECKBOX ck_path7 -20 +25 20 .
              EDIT ed_path7 +20 @ 400 ., default(r(envpath7_text)) nomemory
              CHECKBOX ck_path8 -20 +25 20 .
              EDIT ed_path8 +20 @ 400 ., default(r(envpath8_text)) nomemory
          
          
            TEXT    tx_searchpath 10 +40 200 ., label("Add another search path:")
            FILE    new_path      @  +20 400 ., directory label("Browse . . . ") nomemory
          
            TEXT    tx_sp_rd1     10 +20 200 ., label("Search depth specific to this search path (optional)")
            SPINNER sp_recdepth   @  +25 50  ., option(sp_rd) min(0) max(25) default(4) nomemory
          
            BUTTON  btn_envpath   @  +25 200 ., label("Add path to possible options") onpush(program add_searchpath)
          
          END
          
          // -------------------- define the scripts used in this dialog box ---------
          
            PROGRAM add_searchpath
              BEGIN
          
                  call create STRING newreprootpath
                  call newreprootpath.setvalue searchpaths.new_path
          
                  call searchpaths.ed_path6.setvalue "abc"
                  call searchpaths.ed_path7.setvalue searchpaths.new_path
                  call searchpaths.ed_path8.setvalue newreprootpath
          
              END
          
          
          // -------------------- define the u-action and helper buttons ---------
          OK ok1, label("OK")
          CANCEL can1, label("Cancel")
          HELP hlp1, view("help reproot")
          
          // --------------------------- define how to assemble u-action ---------
          PROGRAM command
            BEGIN
              put "reproot_output_test2"
            END

          Comment


          • #6
            In your PROGRAM add_searchpath, change
            Code:
            call searchpaths.ed_path7.setvalue searchpaths.new_path
            to
            Code:
            call searchpaths.new_path.withvalue searchpaths.ed_path7.setvalue "@"

            Comment


            • #7
              Hi again,

              Sorry that I keep asking questions, but this last nut I have not been able to crack and I have not found anything in the documentation about it.

              I have made the dialogue box work well on my Windows machine. I have made it work on different windows machine, but before finishing up the integration I tested on a Mac as well. However, not everything worked the same. It was specifically loading file paths using this

              Code:
               
              TEXT    tx_searchpath 10 +40 200 ., label("Add another search path:")
              FILE    new_path      @  +20 400 ., directory label("Browse . . . ") nomemory
              BUTTON  btn_searchpath   @  +25 200 ., label("Add path to possible options") onpush(program add_searchpath)
              Do you know if there is anything specific one have to do to make a dialogue box's interaction with the file system work the same way on Windows as on Macs?

              Comment

              Working...
              X