Programming Guide:xppguide

Applications in character mode (VIO mode) Foundation

This section describes the most important commands, functions, and dialog concepts used in programming VIO applications. With only a few exceptions, all relevant language elements of Xbase++ are compatible with Clipper. Programmers familiar with Clipper can just read the "Keyboard and mouse" and "The default Get system" sections of this chapter. Note that the functionality of a VIO application is guaranteed in hybrid mode as well as in GUI mode.

Unformatted input and output

The simplest form of data input and output is unformatted. Data is input or output at the current position of the screen cursor or print head. Xbase++ provides a set of commands for unformatted input and output. These are listed in the following table:

Commands for unformatted input and output
Command Description
? | ?? Output the result of one or more expressions
ACCEPT Input characters at the current cursor position
DISPLAY Output the contents of a database file
INPUT Input an expression at the current cursor position
LIST Output the contents of a database file
SET ALTERNATE Turn output to a file on or off
SET COLOR Set the screen color
SET CONSOLE Turn screen output on or off
SET PRINTER Turn printer output on or off
TEXT...ENDTEXT Output one or more lines of text
TYPE Output the contents of any file
WAIT Input a single character

The three commands ACCEPT, INPUT and WAIT provide unformatted input. WAIT accepts a single keystroke while ACCEPT and INPUT allow any number of characters to be entered. Input via ACCEPT and INPUT is ended when the user presses the Enter key. Characters entered using INPUT are considered as an expression and are compiled using the macro operator (an error in the expression leads to a runtime error). Characters entered using the ACCEPT command remain unchanged and can be assigned to a memory variable as a character string.

The most commonly used commands for unformatted output are the single and the double question marks (? or ??). These are equivalent to the functions QOut() and QQOut(), respectively. The results of one or more expressions can be output using these commands. The default output device is the screen. The results of the expressions can also be saved in a file (after SET ALTERNATE ON) or sent to a printer (after SET PRINTER ON). If the command SET CONSOLE OFF is called before output, screen output is suppressed. After screen output has been suppressed, the screen output must be reactivated using SET CONSOLE ON after output to the file and/or printer is complete.

The commands LIST and DISPLAY are both used to output records from a database file. The command TYPE outputs the contents of any text file. The options TO PRINTER and TO FILE are valid with all three of these commands, so simultaneous output to a printer or a file can be performed without calling SET PRINTER ON or SET ALTERNATE ON. The screen output of these commands can be suppressed by first calling SET CONSOLE OFF.

The command SET COLOR changes the color for the display of screen output. The command is not really an output command, but allows the color of the output to be modified.

Detailed descriptions of the commands for unformatted input and output, including program examples, are found in the reference documentation.

Formatted input and output

Formatted input and output allows the exact position on the screen or printer (the row and column) for data input or output to be specified. Xbase++ includes commands and functions for formatted input and output. The commands are translated by the preprocessor to the equivalent function, which means that the difference between commands and functions is just a difference in syntax. The command syntax sometimes allow more readable program code, since many commands imply several function calls and the command syntax provides additional keywords. The following table lists the most important functions and commands for formatted input and output:

Commands and functions for formatted input and output
Command/function Description
@ Position screen cursor and delete screen line
@...BOX Output box on the screen
@...CLEAR Delete screen area
@...GET Input data
@...SAY Output data
@...TO Output box on the screen
CLEAR Delete entire screen
Col() Return column position of screen cursor
DispOut() Output the result of an expression, and update cursor position
DispOutAt() Like DispOut() but cursor position not updated
DevOut() Output expression results on the current output device
Row() Return row position of screen cursor
MaxCol() Return maximum number of columns on the screen
MaxRow() Return maximum number of rows on the screen
PCol() Return current column position of the print head
PRow() Return current row position of the print head
SaveScreen() Save screen area
SET DEVICE Specify current output device
SetColor() Set or return screen color
SetPos() Change screen cursor position
SetPrc() Set row and column coordinates of the print head
RestScreen() Redisplay a saved screen area

Some of these functions and commands affect only the position of the screen cursor but are included because the cursor coordinates mark the position where data is displayed. Other functions and commands manage the screen itself. In VIO mode, the origin (0, 0) of the coordinate system is the upper left corner of the screen or window. The lower right corner (MaxRow(), MaxCol()) represents the largest coordinate values that are visible. The position of the cursor is set by specifying the Row() and Col() to either the command @ or the function SetPos(). The screen is generally cleared using CLEAR at the start of each program prior to displaying anything for the first time. The commands @...BOX and @...TO draw boxes on the screen. They are only valid for the screen and are not available for the printer.

The most important command for formatted output is @...SAY which outputs the result of an expression. Output using @...SAY can occur on the screen or on the printer. Formatted output differs from unformatted output in that simultaneous output on the screen and printer is not possible. Selecting an output device is done using the command SET DEVICE (TO PRINTER or TO SCREEN). Output on the printer is at the current position of the print head which can be set using the functions PRow() and PCol(). The function SetPrc() resets the internal values for the row and column coordinates of the print head but does not reposition the print head.

The command @...SAY can be expanded to include data input using the GET option. Alternatively, an input field can be defined using the command @...GET. These commands are used to define one or more data entry fields prior to the actual data input which occurs within the READ command or the function ReadModal(). READ and ReadModal() both activate the default Get system of Xbase++ (see the later section on this).

Keyboard and mouse

Under an operating system with graphic user interface, the mouse (not the keyboard) is the most important input device for controlling the application. Because of this, running programs or individual modules is not controlled by program logic but by "events". These events are usually caused by actions of the user. Events, which come from outside the application, are temporarily stored by the operating system in an event queue and then sequentially processed by the application. Some examples of events would be: the mouse was moved, the right mouse button was clicked, the left mouse button was double clicked, etc. A keypress is also an event, which shows that events can come from various devices.

Each event is identified within the program by a numeric code. Each key has an associated unique numeric value and different mouse events have different numeric codes. In Xbase++, events are all handled by a group of event functions, regardless of their origin. There is also a group of functions and commands which assure language compatibility with Clipper. These compatibility functions and commands can only respond to the keyboard and they only consider the keyboard codes defined in Clipper. It should be noted that the numeric values associated with the various keys in Clipper do not necessarily match the event codes of the operating system or Xbase++ and the old keycodes are offered only for compatibility. A correlation is found between key codes and ASCII characters only in the range of 0 to 255. These compatibility functions and commands only consider the key codes defined in Clipper. The distinction between "event functions" and "keyboard functions and commands" is also shown in the following tables:

Event functions supporting both keyboard and mouse input
Function Description
AppEvent() Read event and remove it from the queue
LastAppEvent() Return the last event
NextAppEvent() Read next event without removing it from queue
PostAppEvent() Put event into the queue
SetAppEvent() Associate event with a code block
SetMouse() Toggle availability of mouse events on or off

Keyboard functions and commands supporting only keyboard input
Function / Command Description
Inkey() Read key code
KEYBOARD Write characters into keyboard buffer
LastKey() Return last key code
NextKey() Read next key code
SetKey() Associate key code with a code block

A detailed description of the compatibility functions can be found in the reference documentation.

AppEvent() reads events from the queue and also removes them from the queue. The return value of AppEvent() is the numeric code that uniquely identifies the event. The function SetMouse(.T.) must have been previously called for the AppEvent() function to register mouse events in VIO mode. The following program example is terminated when the right mouse button is pressed:

#include "" 

   LOCAL nEvent := 0 

   @ 0,0 SAY "Press right mouse button to terminate" 
   SetMouse(.T.)                       // register mouse events 

   DO WHILE nEvent <> xbeM_RbDown      // event: right mouse button 
      nEvent := AppEvent(,,,0)         // wait until event occurs 

      IF nEvent < xbeB_Event           // event: keypress 
         ? "The event code for the key is:", nEvent 
         ? "The event code for the mouse is:" , nEvent 


The large number of possible events makes it impractical to directly program events using the numeric codes. Instead, the constants defined in the #include file APPEVENT.CH should be used. These constants all begin with the prefix xbe (which stands for xbase event) followed by an uppercase letter or an underscore. The uppercase letter identifies the category for the event and the underscore separates the prefix from the rest of the descriptive event name:

Event categories
Category Prefix Example
No event xbe_ xbe_None
Keyboard event xbeK_ xbeK_RETURN
Base event xbeB_ xbeB_Event
Mouse event xbeM_ xbeM_LbDown
Xbase Part event xbeP_ xbeP_Activate

In addition to the return value identifying the event, the function AppEvent() modifies two parameters that are passed by reference. These are called "message parameters" and contain additional information about the event. In an event driven system such as Xbase++, it is often insufficient to receive only a single event code. For example, it is generally necessary to know the position of the mouse pointer if the event is "mouse click". When the function AppEvent() is called, two parameters must be passed by reference to contain additional information about the event after AppEvent() returns. If the event is a mouse click, the coordinates of the mouse pointer are contained in the first message parameter as an array of two elements. The following example illustrates this:

#include "" 

   LOCAL nEvent := 0, mp1, nRow, nCol 

   @ 0,0 SAY "Press right mouse button to cancel" 
   SetMouse(.T.)                       // register mouse event 

   DO WHILE nEvent <> xbeM_RbDown      // event: right mouse button 
      nEvent := AppEvent(@mp1,,,0)     // wait until event 
                                       // occurs 
      IF nEvent < xbeB_Event           // event: keypress 
         ? "Event code:", nEvent 
      ELSEIF nEvent <> xbeM_Motion     // mouse events exept 
                                       // 'mouse moved' 
         nRow := mp1[1]                // mouse coordinates 
         nCol := mp1[2] 
         @ nRow, nCol SAY "The event code is:" + Str(nEvent) 


The variable mp1 is passed by reference to the function AppEvent(). After each mouse event it contains the row and column coordinates of the mouse pointer in an array of two elements. In the example, the contents of the array are assigned to the two variables nRow and nCol. The event code is output at this position, unless it is a mouse movement. The xbeM_Motion event occurs very frequently during mouse movement and would clutter the screen if displayed.

In VIO mode, the mouse coordinates are the most important information contained in the message parameters. In many other cases the parameters contain the value NIL in this operating mode but contain additional information when Xbase Parts are used (of course, Xbase Parts are not available in VIO mode) or when user-defined events are created using the function PostAppEvent(). The following example illustrates the basic relationship between the functions AppEvent() and PostAppEvent() which (along with their message parameters) create the basis for event driven programming:

#include "" 

#define  xbeU_DrawBox  xbeP_User + 1   // xbeP_User is the base value 
#define  xbeU_Quit     xbeP_User + 2   // for User events 

   LOCAL nEvent := 0, mp1, mp2 

   @ 0,0 SAY " Draw Box |  QUIT"       // mouse sensitive region 
   SetMouse(.T.)                       // register mouse 

   DO WHILE .T.                        // infinite event loop 
      nEvent := AppEvent( @mp1, @mp2 ,,0 ) 

      DO CASE 
      CASE nEvent == xbeU_DrawBox      // user event 
         DrawBox( mp1, mp2 )           // mp1 = Date(), mp2 = Time() 
                                       // from PostAppEvent() 
      CASE nEvent == xbeU_Quit         // second user event 

      CASE nEvent < xbeB_Event         // key was pressed 
         @ MaxRow(), 0 
         ?? "Key code is:", nEvent 

      CASE nEvent == xbeM_LbClick      // left mouse button click 
         @ MaxRow(), 0 
         ?? "Coordinates are:", mp1[1], mp1[2] 

         IF mp1[1]== 0 .AND. mp1[2] <= 21 // in mouse sensitive 
                                          // region 
            IF mp1[2] <= 15 
               PostAppEvent( xbeU_DrawBox, Date(), Time() ) 
               PostAppEvent( xbeU_Quit ) 
            @ mp1[1], mp1[2] SAY "No selection made" 



*********************************      // define position and display 
PROCEDURE DrawBox( dDate, cTime )      // box using mouse clicks 
   LOCAL nEvent := 0, mp1, nTop, nLeft, nBottom, nRight 

   @ 0, 0 SAY "Click on upper left corner of box" 

   DO WHILE nEvent <> xbeM_LbClick     // wait for left mouse click 
      nEvent := AppEvent( @mp1,,, 0 ) 

   nTop  := mp1[1] 
   nLeft := mp1[2] 

   nEvent := 0 
   @ nTop, nLeft SAY "Click on lower right corner of box" 

   DO WHILE nEvent <> xbeM_LbClick     // wait for left mouse click 
      nEvent := AppEvent( @mp1,,, 0 ) 

      IF nEvent == xbeM_LbClick .AND. ; 
         ( mp1[1] <= nTop .OR. mp1[2] <= nLeft ) 
         Tone(1000,1)                  // lower right corner 
         nEvent := 0                   // is invalid 

   nBottom  := mp1[1] 
   nRight   := mp1[2] 

   @ nTop, nLeft TO nBottom, nRight    // output box 

   @ nTop+1,nLeft+1 SAY "Date:"        // display values of 
   ?? dDate                            // PostAppEvent() 
   @ nTop+2,nLeft+1 SAY " Time:" 
   ?? cTime 


In the example, one of the two user-defined events is generated when the mouse is clicked in the hot spot region of the first screen row. The mouse coordinates (contained in the message parameter mp1) are used to distinguish whether the xbeU_DrawBox event or the xbeU_Quit event is placed in the queue by PostAppEvent(). The user-defined event xbeU_DrawBox receives the return values of Date() and Time() as message parameters. When this event is retrieved from the queue by AppEvent(), the message parameters are placed in the variables mp1 and mp2. These values are passed to the procedure DrawBox() and displayed on the screen by this function.

The program is a simple example showing the logic of event driven programming. Events are identified by a unique numeric value (using a #define constant) and additional information about the event is contained in the two message parameters. The values contained in the two parameters mp1 and mp2 vary depending on the event. The message parameter values can range from NIL in the simplest case to complex data structures such as arrays or objects. PostAppEvent() can be used to place any event in the queue that can then be retrieved from any place in the program using AppEvent().

The default Get system

Xbase++ provides a Get system for formatted data input in VIO mode. The source code of this system is contained in the GETSYS.PRG file. The open architecture of the Get system offers tremendous possibilities such as data validation before, during and after data entry. It also offers a specific place where a programmer can identify and process events that occur during data input without having to change the basic language elements for defining input fields.

An input field is most easily created using the command @...SAY...GET. The data entry itself is started using the command READ:

USE Address ALIAS Addr 

@ 10,10 SAY "First Name:" GET Addr->FIRSTNAME  // define data 
@ 12,10 SAY " Last Name:" GET Addr->LASTNAME   // entry fields 

READ                                           // read input 

In these four lines a database file is opened, two data entry fields are defined and input is performed via the READ command. Input is terminated when the entry in the second field is finished using the Return key or if the Esc key is pressed during input.

The command syntax is the easiest way to program data entry fields. This syntax is translated by the preprocessor into code that creates Get objects and stores them in the GetList array. Get objects include methods that allow the formatted display of values and interactive data entry. The data entry values can be contained in memory variables or in field variables. Access to the contents of data entry variables does not occur directly, but through a code block. This code block is called the data code block. The data code block is used by the Get object to read the value of a variable into the Get object's edit buffer and then to write the modified value back into the variable.

When a Get object has input focus, the user can modify the contents of the edit buffer. A Get object uses various methods to control cursor navigation and transfer characters into the edit buffer. Get objects can also perform data validation before and after data input. Rules for data validation are specified in code blocks contained in instance variables of the Get object.

The command @...GET creates a Get object that already contain a code block to access the specified variable. When Get objects are created directly using the class method Get():new(), a data code block must be specified. Get objects are stored in an array that is passed to the function ReadModal(). If the @...GET command is used, the array referencing the Get objects is contained in the variable GetList. The READ command passes the GetList array to the function ReadModal(). The ReadModal() function is the default edit routine which accesses various edit and display methods of the Get objects. The default Xbase++ Get system includes the ReadModal() function along with the other globally visible utility routines listed in the following table:

Functions of the Get system

READ Service routines
Function Description
ReadModal() Activates data input for all Get objects
ReadExit() Defines termination keys for data entry fields
ReadInsert() Toggles between insert and overwrite mode
ReadKill() Terminates data input for all Get objects in the current GetList array

GET Service routines
Function Description
GetEventReader() Get Reader for AppEvent()
GetHandleEvent() Allows event processing by current Get object
GetPrevalidate() Prevalidates before a Get object receives focus
GetPostvalidate() Postvalidates before a Get object loses focus
GetDoSetkey() Executes code block which is linked to a key or an event
GetActive() Sets the Get object that has the focus
GetKillActive() Removes focus from the active Get object
Getlist() Determines current GetList array
GetlistPos() Returns position of current Get object in the GetList array
GetEnableEvents() Toggles between Inkey() and AppEvent()
GetToMousePos() Positions cursor in entry field at the mouse pointer

Compatibility functions supporting only keyboard entry
Function Description
GetReader() Get reader for Inkey()
GetApplykey() Allows keys to be processed by the current Get object

Two of the functions in the GETSYS.PRG file exist in order to ensure compatibility with the Clipper Get system. In these functions, the compatibility function Inkey() is used to retrieve keyboard entry. This is not compatible with the AppEvent() function which is used to read Xbase++ events. To make it easier to port existing Clipper applications to Xbase++, the compatibility functions are used by default in VIO mode. This means that the Get system reads only the keyboard using Inkey() and does not process any events. In this default mode, the Get system is completely compatible with Clipper but the mouse is not available.

The default setting is switched when SetMouse(.T.) is called before the first READ command or the first call to ReadModal(). Events in the Get system are then processed using the functions GetEventReader() and GetHandleEvent() instead of the functions GetReader() and GetApplykey(). In this setting the mouse is available. The function SetAppEvent() must be used instead of SetKey() to associate keystrokes with code blocks. The function GetEnableEvents( .T. | .F.) can also be used to switch between the compatibility mode and the event driven mode of the Xbase++ Get system.

The service functions of the Get system are rarely needed. The @...SAY...GET command is sufficient to allow complex data entry screens to be easily programmed. A detailed knowledge of the additional Get system functions is required when the default Get system is modified to meet unique requirements.

Modification of the Get system

The source code of the Xbase++ Get system is contained in the file GETSYS.PRG and can be modified in just about any way. Changes should not be performed in the file itself but in a copy of the file. Before substantial changes to GETSYS.PRG are performed, other ways to modify the default behavior to meet individual requirements should be explored. For example, the instance variable oGet:reader contains a code block that calls a user-defined Get reader that can be used to provide special features. The Get reader code block must accept one parameter (the Get object) which must be passed as the first parameter to the function or procedure that implements the Get reader. The basic approach to implementing a special Get reader is shown in the following example. This code uses the compatibility function Inkey() to read keyboard input. The purpose of the example reader is to handle German language umlauts and "ß" entered as characters in the entry field. These characters are translated into their two character equivalents in the user-defined reader NoUmlauts() :

#include "" 

   LOCAL cName1 := Space(20),  cName2 := Space(20) 

   @  8,10 SAY "Input without umlauts and ß" 

   @ 10,10 SAY "First Name:" GET cName1 ;    // define Get Reader 
                          SEND reader := {|oGet| NoUmlauts(oGet) } 
   @ 12,10 SAY " Last Name:" GET cName2 ; 
                          SEND reader := {|oGet| NoUmlauts(oGet) } 


The definition of these input fields occurred using the command syntax. The code block which assigns the user-defined Get reader is specified using the SEND option. In it the reader code block is assigned to the instance variable oGet:reader. The Get reader itself is programmed in the following procedure:

PROCEDURE NoUmlauts( oGet ) 
   LOCAL bBlock, cChar, nKey 

   IF GetPreValidate( oGet )           // perform prevalidation 
      oGet:setFocus()                  // set input focus to Get 

      bBlock := {|o,n1,n2| ;           // translate within the code 
         GetApplykey(o,n1),;           // block into two characters 
         IIf( o:typeOut, NIL, GetApplykey(o,n2) ) } 

      DO WHILE oGet:exitState == GE_NOEXIT 

         IF oGet:typeOut               // no editable characters 
            oGet:exitState := GE_ENTER // right of the cursor 

         DO WHILE oGet:exitState == GE_NOEXIT 
            nKey := Inkey(0)           // read keyboard 
            cChar:= Chr(nKey) 

            DO CASE                  // translate special characters 
            CASE cChar == "Ä" 
               Eval( bBlock, oGet, Asc("A"), Asc("e") ) 
            CASE cChar == "Ö" 
               Eval( bBlock, oGet, Asc("O"), Asc("e") ) 
            CASE cChar == "Ü" 
               Eval( bBlock, oGet, Asc("U"), Asc("e") ) 
            CASE cChar == "ä" 
               Eval( bBlock, oGet, Asc("a"), Asc("e") ) 
            CASE cChar == "ö" 
               Eval( bBlock, oGet, Asc("o"), Asc("e") ) 
            CASE cChar == "ü" 
               Eval( bBlock, oGet, Asc("u"), Asc("e") ) 
            CASE cChar == "ß" 
               Eval( bBlock, oGet, Asc("s"), Asc("s") ) 
               GetApplykey( oGet, nKey ) 


         IF ! GetPostValidate( oGet ) 
            oGet:exitState:= GE_NOEXIT // postvalidation 
         ENDIF                         // has failed 

      oGet:killFocus()                 // set back input focus 



Within the user-defined Get reader NoUmlauts(), keys are read using Inkey(). The keyboard input is then tested to see if it includes one of the German language characters Ä, Ö, Ü, ä, ö, ü and ß. If one of these characters is present, it is translated to the two equivalent characters Ae, Oe, Ue, ae, oe, ue, or ss. All other characters are passed along with the Get object to the function GetApplykey() which defines the default behavior for transferring characters into the edit buffer of Get objects.

In order to modify this Get reader to use the function AppEvent() for reading events (instead of just keystrokes), additional variables must be declared for the message parameters passed by reference to AppEvent(). Instead of GetApplykey(), the function GetHandleEvent() must be used for default handling of other events.

Display of tables

Along with formatted data input using @...SAY...GET with READ or using Get objects with ReadModal(), displaying an entire table is an important and frequently used interface feature. A table allows the user to interactively view large amounts of data. Data in a table is organized into rows and columns. This data can be from a database file open in a work area or from an array stored in memory. The TBrowse class and the TBColumn class are included in Xbase++ to allow tables to be displayed. These classes are used together but each performs a specific set of tasks when displaying tables. Table display is possible only through the combined efforts of objects of both classes. A TBrowse object performs the screen display and controls the current row and column of a table. A TBColumn object provides the data for a column of the table displayed by the Tbrowse object. TBColumn objects must be assigned to the TBrowse object and are used by the TBrowse object when a user views a table.

Classes for the display of tables and database files
Class Description
TBrowse() Browsing of data that can be represented as a table of rows and columns
TBColumn() Display a single column of data in the browse window of the TBrowse object

The TBrowse and TBColumn classes are associated with a set of functions that exist in Xbase++ only to provide compatibility with Clipper. The source code for the compatibility functions listed in the following table are contained in the files DBEDIT.PRG, BROWSYS.PRG and BROWUTIL.PRG.

Compatibility functions for the display of tables and database files
Function Description
Browse() Browse database file, including DELETE and APPEND
DbEdit() Browse database file with UDF control
TBrowseNew() Create TBrowse object
TBrowseDb() Create TBrowse object for database file
TBColumnNew() Create TBColumn object

TBrowse objects provide a versatile mechanism for displaying data in the form of a table. TBrowse objects display tabular data in a defined section of the screen (the browse window).

Tables are often too large to be entirely displayed on the screen. TBrowse objects provide methods that allow tables to be viewed interactively on the screen. The TBrowse class is designed so that an object of this class does not know anything about the data source it displays. To display data, a TBrowse object relies on one or more objects of the TBColumn class to provide the data for individual columns in the table. A TBrowse object displays the data provided by the TBColumn objects on the screen. Each TBColumn object deals with only one column of the associated table. The TBrowse object manages its own cell cursor and displays the data in the current row and column of a table (the current cell) in a highlighted color.

A user can position the cell cursor in the table using the cursor keys. A TBrowse object includes many methods which move the cell cursor. As soon as the user tries to move the cell cursor out of the Browse window, the TBrowse object automatically synchronizes the visible data on the screen with the data of the underlying table and scrolls the data in the browse window.

Since the data source of the table is not known to the TBrowse object, three functions must be specified to execute the three basic operations that can be performed on a table: jump to the start of the table, jump to the end of the table and change the current row within the table. These operations are comparable to the file commands GO TOP, GO BOTTOM and SKIP. These functions are provided to TBrowse objects as code blocks that are automatically executed within specific methods of the TBrowse object.

The browse window where the TBrowse object displays tabular data can be divided into three areas: headers or column titles, data lines containing the data, and footers at the bottom of each column. Each area, as well as each individual column, can be optionally delimited by a separating line.

In contrast to TBrowse objects, TBColumn objects are very simple objects that contain instance variables but do not have their own methods. TBColumn objects are needed to provide data for tables displayed using TBrowse objects and are useless without an associated TBrowse object. A TBColumn object contains in its instance variable all of the information required for displaying a single column of a table in the browse window of the TBrowse object.

The most important TBColumn instance variable (:block) contains a data code block that provides the data from the data source for a column of data. This code block might access a field variable in a work area, or a column in an array. TBColumn objects can also control the color of the data displayed based on its value.

If new values are assigned to the instance variables of a TBColumn object after the TBrowse object has already displayed data using the TBColumn object, the method oTBrowse:configure() must be executed to update the columns in the browse window (see TBrowse class).


If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.