TFolder

Tab folder control for organizing complex dialogs into pages

Source: source/classes/folder.prg  |  Parent: TControl

Overview

TFolder implements a Windows tab control. Each tab page is an independent TDialog object, so you can place any controls on each page using standard dialog syntax. The folder manages which page is visible when the user clicks a tab.

Key features:

Page Composition

graph TD PARENT["TDialog / TWindow
(Parent)"] --> FOLDER["TFolder"] FOLDER --> TAB1["Tab 1: General"] FOLDER --> TAB2["Tab 2: Details"] FOLDER --> TAB3["Tab 3: Notes"] TAB1 --> DLG1["aDialogs[1]
TDialog"] TAB2 --> DLG2["aDialogs[2]
TDialog"] TAB3 --> DLG3["aDialogs[3]
TDialog"] DLG1 --> C1["TGet, TComboBox,
TCheckBox, ..."] DLG2 --> C2["TXBrowse, TButton, ..."] DLG3 --> C3["TMGet (memo), ..."] style FOLDER fill:#1c2129,stroke:#58a6ff,stroke-width:2px,color:#e6edf3 style DLG1 fill:#1c2129,stroke:#3fb950,stroke-width:1px,color:#e6edf3 style DLG2 fill:#1c2129,stroke:#3fb950,stroke-width:1px,color:#e6edf3 style DLG3 fill:#1c2129,stroke:#3fb950,stroke-width:1px,color:#e6edf3

Key Properties

PropertyTypeDescription
aPromptsArrayArray of strings for each tab label (e.g. {"General", "Details", "Notes"})
aDialogsArrayArray of TDialog objects, one per tab page
nOptionNumericIndex of the currently selected tab (1-based). Set this to switch pages programmatically.
oImageListObjectOptional TImageList providing icons for each tab
bChangeBlockCode block executed when the user switches tabs
lBottomLogicalWhen .T., tabs appear at the bottom instead of the top
nTabHeightNumericHeight of the tab strip in pixels

Key Methods

MethodDescription
New( nRow, nCol, oWnd, aPrompts, ... )Constructor. Creates the folder with the given tab labels.
AddPage( cPrompt, oDlg )Add a new page at runtime.
DelPage( nPage )Remove a page at runtime.
SetOption( n )Switch to page n programmatically.
GetPage( n )Returns the TDialog for page n.

Command Syntax

@ nRow, nCol FOLDER oFld ;
   OF oDlg ;
   PROMPTS "Tab1", "Tab2", "Tab3" ;
   DIALOGS oDlg1, oDlg2, oDlg3 ;
   [ SIZE nWidth, nHeight ] ;
   [ ON CHANGE bChange ] ;
   [ BOTTOM ]

Each dialog variable (oDlg1, oDlg2, oDlg3) is automatically created as a child TDialog. You then place controls on each page dialog in the ACTIVATE DIALOG block.

Tab Navigation Flow

stateDiagram-v2 [*] --> Page1 : Folder created Page1 --> Page2 : Click tab 2 Page2 --> Page3 : Click tab 3 Page3 --> Page1 : Click tab 1 Page1 --> PageN : SetOption(N) PageN --> Page1 : SetOption(1) state Page1 { [*] --> DLG1_Visible DLG1_Visible : aDialogs[1] shown DLG1_Visible : Other pages hidden } state Page2 { [*] --> DLG2_Visible DLG2_Visible : aDialogs[2] shown DLG2_Visible : Other pages hidden } state Page3 { [*] --> DLG3_Visible DLG3_Visible : aDialogs[3] shown DLG3_Visible : Other pages hidden }

Code Examples

Example 1: Customer Edit Dialog with Tabs

#include "FiveWin.ch"

FUNCTION CustomerEdit()
   LOCAL oDlg, oFld, oFont
   LOCAL oDlg1, oDlg2, oDlg3
   LOCAL cName   := "John Smith"
   LOCAL cPhone  := "(555)123-4567"
   LOCAL cEmail  := "john@example.com"
   LOCAL cAddr   := "123 Main St"
   LOCAL cCity   := "New York"
   LOCAL cState  := "NY"
   LOCAL cZip    := "10001"
   LOCAL nCredit := 5000.00
   LOCAL cNotes  := "VIP customer since 2015"
   LOCAL lActive := .T.

   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -14

   DEFINE DIALOG oDlg TITLE "Edit Customer" ;
      SIZE 520, 420 FONT oFont

   // Create the folder with 3 tabs
   @ 0.5, 0.5 FOLDER oFld ;
      OF oDlg ;
      PROMPTS "General", "Address", "Notes" ;
      DIALOGS oDlg1, oDlg2, oDlg3 ;
      SIZE 490, 310

   // --- Page 1: General ---
   @ 1.0, 1 SAY "Name:" OF oDlg1
   @ 1.0, 5 GET cName OF oDlg1 SIZE 200, 22 PICTURE "@!"

   @ 2.5, 1 SAY "Phone:" OF oDlg1
   @ 2.5, 5 GET cPhone OF oDlg1 SIZE 140, 22 PICTURE "(999)999-9999"

   @ 4.0, 1 SAY "Email:" OF oDlg1
   @ 4.0, 5 GET cEmail OF oDlg1 SIZE 220, 22

   @ 5.5, 1 SAY "Credit Limit:" OF oDlg1
   @ 5.5, 5 GET nCredit OF oDlg1 SIZE 120, 22 PICTURE "@E 99,999.99"

   @ 7.0, 1 CHECKBOX lActive PROMPT "Active Customer" OF oDlg1

   // --- Page 2: Address ---
   @ 1.0, 1 SAY "Street:" OF oDlg2
   @ 1.0, 5 GET cAddr OF oDlg2 SIZE 280, 22

   @ 2.5, 1 SAY "City:" OF oDlg2
   @ 2.5, 5 GET cCity OF oDlg2 SIZE 180, 22

   @ 4.0, 1 SAY "State:" OF oDlg2
   @ 4.0, 5 GET cState OF oDlg2 SIZE 40, 22 PICTURE "!!"

   @ 4.0, 9 SAY "ZIP:" OF oDlg2
   @ 4.0, 11 GET cZip OF oDlg2 SIZE 80, 22 PICTURE "99999"

   // --- Page 3: Notes ---
   @ 0.5, 1 GET cNotes MEMO OF oDlg3 SIZE 440, 200

   // Buttons below the folder
   @ 24, 12 BUTTON "&Save"   OF oDlg SIZE 80, 25 ACTION oDlg:End() DEFAULT
   @ 24, 22 BUTTON "&Cancel" OF oDlg SIZE 80, 25 ACTION oDlg:End() CANCEL

   ACTIVATE DIALOG oDlg CENTERED

   RELEASE FONT oFont
RETURN NIL

Example 2: Folder with Browse and Dynamic Page Switching

#include "FiveWin.ch"
#include "XBrowse.ch"

FUNCTION DataViewer()
   LOCAL oDlg, oFld, oBrw
   LOCAL oDlg1, oDlg2
   LOCAL aLog := { ;
      { "2026-03-24 09:00", "Login",  "admin" }, ;
      { "2026-03-24 09:15", "Edit",   "admin" }, ;
      { "2026-03-24 10:00", "Export", "user1" }  ;
   }

   DEFINE DIALOG oDlg TITLE "Data Viewer" SIZE 600, 450

   @ 0.2, 0.2 FOLDER oFld ;
      OF oDlg ;
      PROMPTS "Browse Data", "Activity Log" ;
      DIALOGS oDlg1, oDlg2 ;
      SIZE 570, 340

   // Notify when tab changes
   oFld:bChange := {|| MsgBeep() }

   // --- Page 1: XBrowse of a DBF ---
   USE Customer VIA "DBFCDX" NEW
   oBrw := TXBrowse():New( oDlg1 )
   oBrw:SetRDD()
   oBrw:CreateFromCode()
   oDlg1:oClient := oBrw

   // --- Page 2: XBrowse of an array ---
   LOCAL oBrw2 := TXBrowse():New( oDlg2 )
   oBrw2:SetArray( aLog )
   oBrw2:aCols := {}
   oBrw2:AddColumn( "Timestamp", {|| aLog[ oBrw2:nArrayAt ][ 1 ] } )
   oBrw2:AddColumn( "Action",    {|| aLog[ oBrw2:nArrayAt ][ 2 ] } )
   oBrw2:AddColumn( "User",      {|| aLog[ oBrw2:nArrayAt ][ 3 ] } )
   oBrw2:CreateFromCode()
   oDlg2:oClient := oBrw2

   // Buttons
   @ 27, 18 BUTTON "&Close" OF oDlg SIZE 80, 25 ACTION oDlg:End() CANCEL

   // Jump to Activity Log tab programmatically
   @ 27, 2 BUTTON "Show &Log" OF oDlg SIZE 100, 25 ;
      ACTION oFld:SetOption( 2 )

   ACTIVATE DIALOG oDlg CENTERED

   CLOSE Customer
RETURN NIL

Tips

See Also