Ask Reuben

Show Folder Page

How do I show a particular folder page?

Why is a particular folder page shown?

The FOLDER and PAGE containers combine to show the contents of one particular PAGE.  The user can then click on the Page Header to show another particular PAGE.

It is very useful for cases where you want to display more content in one window then would sensibly fit (although I would think that in some cases the use of the new collapsible group boxes would be more appropriate).  The pages can also be used to imply some grouping of logical fields and/or to show progress from left to right like a wizard.

The key property of a FOLDER and PAGE is that only one PAGE is ever shown at a time, the user is expected to click on the page header or tab to show another page.

The questions we get asked relate to how to control what particular folder page is shown.

The answer to that question is that the front-end will display the Folder Page that contains the field with the focus.  If you programmatically want to change the page shown, do a NEXT FIELD to a field on the page you want to show so that it has the focus, or if you have a singular dialog on each page, in your 4gl switch to that dialog (by implication the field with focus will now be on the desired page)

However there are situations where the dialog might not have a field with focus e.g. MENU, or the field with focus might be outside of the FOLDER e.g.

VBOX
GRID
{
...
Field with Focus [f01    ]
...
}
END
FOLDER
PAGE page1 (TEXT="Page One")
...
PAGE page2 (TEXT="Page Two")
...
END #PAGE
END #FOLDER
END #VBOX
END #LAYOUT

The technique then is to use the ui.Form.ensureElementVisible method.  If you ensure that you have given the PAGE container a name, you can pass that as the argument to the ensureElementVisible method.  (Note: you can also use the ensureFieldVisible method and reference a field on the page but I think the ensureElementVisible method and using page name as argument is more readable).

This little example shows it being used to change the visible page …

#! folderpage.4gl
MAIN
    DEFINE current_page STRING

    OPEN WINDOW w WITH FORM "folderpage"

    LET current_page = "page_one"
    MENU ""
        ON ACTION close
            EXIT MENU
        ON TIMER 1
            CALL ui.Window.getCurrent().getForm().ensureElementVisible(current_page)
            CALL ui.Interface.refresh()
            CASE current_page
                WHEN "page_one"
                    LET current_page = "page_two"
                WHEN "page_two"
                    LET current_page = "page_three"
                WHEN "page_three"
                    LET current_page = "page_one"

            END CASE

    END MENU
END MAIN



#!folderpage.per
LAYOUT (TEXT="Show Folder Page")
FOLDER
PAGE page_one (TEXT="Page One")
GRID
{
Page One
}
END
END
PAGE page_two (TEXT="Page Two")
GRID
{
Page Two
}
END
END
PAGE page_three (TEXT="Page Three")
GRID
{
Page Three
}
END
END
END
END 

… if you run the above, you should see the current folder page changing every second.

There are two other techniques you may see.

The first involves a case using an active multiple dialog and there maybe a display array on particular pages.  Your dialog ends up looking like

DIALOG
   DISPLAY ARRAY ... -- on page 2
   DISPLAY ARRAY ... -- on page 3
END DIALOG

but you want to give page 1 the focus and so you may see

DIALOG
   INPUT ...         -- field on page 1
   DISPLAY ARRAY ... -- on page 2
   DISPLAY ARRAY ... -- on page 3
END DIALOG

You could split this up into a singular dialog for each page and using the ACTION attribute for a PAGE container to trigger ON ACTION, but by using a multiple dialog you do not need to explicitly code the ON ACTION to handle the user clicking on the Page header, and so you see the above solution where there is an INPUT to a dummy field on a particular page so that if the user clicks on that PAGE, the focus is put on the dummy field.  That is a technique I use here https://github.com/FourjsGenero/fgl_auitree/blob/master/auitree_test.per and if you look closely at the field I use presentation styles to hide the field

<Style name=".dummy" >
      <StyleAttribute name = "fontSize" value = "1pt" ></StyleAttribute>
      <StyleAttribute name = "border" value = "none" ></StyleAttribute>
      <StyleAttribute name = "textColor" value = "transparent" ></StyleAttribute>   
      <StyleAttribute name = "backgroundColor" value = "transparent" ></StyleAttribute>   
</Style> 

… the presentation styles doing everything they can to make the field practically invisible.  On some front-ends it will appear as 1 pixel that flashes so barely noticable.

The second technique dates back from before we introduced the ensureElementVisible method.  What I worked out is that if you hid every page except the one you wanted to show, called ui.Interface.refresh, and then unhid the pages you just hid, at the time of the ui.Interface.refresh only one page is visible and so it will be rendered on top.  If you come across in your libraries a function doing that, you should amend your library to use the ensureElementVisible method.

So in summary, the field with focus will control what folder page is on top and visible, you can use the ui.Form.ensureElementVisible for situations where there may not be a field with focus.