9\. Recommended Usage Pattern
The following is the typical order for configuring an XBrowse completely and correctly:
1\. Define the data source (ALIAS, ARRAY, RECSET, OBJECT)
2\. Create the browse with @ X,Y XBROWSE ... or TXBrowse():New()
3\. Configure browse properties (styles, colors, marquee, scroll)
4\. Configure column properties (headers, editing, colors, bitmaps)
5\. Define group headers if applicable (SetGroupHeader)
6\. Call MakeTotals() if there are footers with aggregates
7\. Call CreateFromCode() — ALWAYS the last step
8\. Assign oWnd:oClient := oBrw (for windows)
9\. Activate the window or dialog with ON INIT oBrw:SetFocus()
📌 NOTE: CreateFromCode() MUST always be the last configuration call. Any property or method called after CreateFromCode() may have no effect.
10\. Advanced Record Selector
The record selector (the left gray column) can be fully customized to show row numbers, names, icons, and context menus.
10.1 Record Selector Properties
| Property / Event | Type | Description and Usage |
| bRecSelData | Block | Content of the selector cell. { | brw | brw:KeyNo} shows sequential number |
| bRecSelHeader | String/Block | Selector header. Ex: oBrw:bRecSelHeader := "SlNo" |
| bRecSelFooter | String/Block | Selector footer. { | brw | brw:nLen} shows total records |
| nRecSelWidth | Numeric/String | Selector width. If string, used as model: "9999" → width for 4 digits |
| nRecSelHeadBmpNo | Numeric/String/Array | Bitmap in selector header. Can be path, number, or line descriptor |
| bRecSelClick | Block | Click on selector header. { | | RecSelPopUp(oBrw)} |
| SetRecSelBmp(xBmp) | Method | Sets custom bitmap in selector. nil=default, 0=no bitmap, cFile=image |
| lRecordSelector | Logical | Shows/hides entire selector. Default: .T. |
| RecSelShowRecNo() | Method | Displays the record number in the selector (convenient shortcut) |
| SetChecks() | Method | Configures all logical fields as checkboxes in the browse |
| SetMultiSelectCol() | Method | Adds automatic multi-selection checkbox column |
| oMultiSelCol | Object | Reference to the multi-selection column created by SetMultiSelectCol() |
| SelectRow() | Method | Returns .T. if the current row is selected (for use with bSumCondition) |
| oRightCol | Object | Column frozen on the RIGHT. Ex: oBrw:oRightCol := oBrw:Salary |
| KeyNo | Numeric | Sequential number of the current row (read property of the browse) |
Example: Selector with row number
WITH OBJECT oBrw
:bRecSelData := { |brw| brw:KeyNo }
:bRecSelFooter := { |brw| brw:nLen }
:bRecSelHeader := "SlNo"
:nRecSelWidth := "9999"
END
Example: Selector with region name (Array)
WITH OBJECT oBrw
:bRecSelData := { |brw| brw:aRow\[ 1 \] } // name in col 1
:bRecSelFooter := "Totals"
:bRecSelHeader := "Region"
:nRecSelWidth := "Americas" // width for the longest text
END
Example: Multi-selection with conditional totals
WITH OBJECT oBrw
:SetMultiSelectCol()
:bClrStd := { || { CLR\_BLACK, If( oBrw:SelectRow(), 0x88EDFB, CLR\_WHITE ) } }
:Salary:bSumCondition := { || oBrw:SelectRow() }
:Salary:nFooterType := AGGR\_SUM
:MakeTotals()
END
11\. GetBar and Incremental Filter
11.1 GetBar — Gets below headers
Allows displaying input fields directly below column headers to filter the browse in real time.
| Property / Event | Type | Description and Usage |
| lGetBar | Logical | Activates/deactivates the GETs bar below headers. Ex: oBrw:lGetBar := .T. |
| uBarGetVal | Various | Initial value of the column GET. Ex: oCol:uBarGetVal := Space(10) |
| cBarGetPic | String | Mask of the GET in the bar. Ex: oCol:cBarGetPic := NumPict(FieldLen(n), FieldDec(n)) |
| bClrEdits | Block | Color of bar GETs. { | | {CLR\_BLACK, CLR\_YELLOW}} |
| oHeaderFonts | Object | Font for headers. Ex: oBrw:oHeaderFonts := oBold |
| AutoFit() | Method | Automatically adjusts column width to content |
11.2 Incremental Filter
Allows filtering the browse while the user types, without needing to press Enter.
| Property / Event | Type | Description and Usage |
| lIncrFilter | Logical | Activates real-time incremental filter. Ex: oBrw:lIncrFilter := .T. |
| lSeekWild | Logical | If .T., filters by content (contains). If .F., filters by beginning (starts with) |
| cFilterFld | String | Name of the field to filter. Ex: oBrw:cFilterFld := "FIRST" |
| cSeek | String | Current search text (read) |
| oSeek | SAY Object | SAY control showing current search text |
| Seek(cText) | Method | Executes the search. Ex: oBrw:Seek("") to clear |
12\. Internal Button Bar (nTopBarHeight / bOnAdjust)
XBrowse allows embedding a button bar directly inside the browse itself, above the data, without needing an external ButtonBar.
| Property / Event | Type | Description and Usage |
| nTopBarHeight | Numeric | Height in pixels of the internal bar. Ex: oBrw:nTopBarHeight := 30 |
| bOnAdjust | Block | Block executed when creating/adjusting the browse. Internal buttons are created here |
| EditSource(\[lNew\]) | Method | Opens editor for current record. lNew=.T. for new. Alias of Edit() |
Complete example
oBrw:nTopBarHeight := 30
oBrw:bOnAdjust := \<||
local oBtn
@ 05,05 BTNBMP oBtn FILE "new.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:EditSource( .T. ) TOOLTIP "Add"
@ 05,45 BTNBMP oBtn FILE "edit.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:EditSource() TOOLTIP "Edit"
@ 05,85 BTNBMP oBtn FILE "delete.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:Delete() TOOLTIP "Delete"
return nil
\>
13\. Fonts and Colors per Line (Advanced Multiline)
XBrowse allows assigning different fonts and colors to each line of text within a multiline cell, using the aDataFont and aClrText properties of the column.
| Property / Event | Type | Description and Usage |
| aDataFont | Array of fonts | Array of font objects per line. Line N uses aDataFont\[N\]. Ex: oCols\[1\]:aDataFont := {oFont1, oFont2} |
| aClrText | Array of colors | Array of text colors per line. nil \= default color. Ex: {CLR\_HBLUE, CLR\_HRED} |
| nDataStrAlign | Numeric | Can combine AL\_CENTER \+ AL\_BOTTOM for vertical+horizontal alignment |
| aImgRect | Array | Image crop in cell: {nTop%, nLeft%, nBottom%, nRight%, cShape}. Shape: "CIRCLE", nil=rect |
| lFitGridHeight | Logical | Adjusts browse height to fit exactly N complete rows |
| nHeadStrAligns | Numeric | Alignment of ALL headers at once (browse property) |
| nWidths | Array/Numeric | If array, sets individual widths: {200, 250, 150}. If numeric, uniform width |
Example: different fonts and colors per line
DEFINE FONT aFont1\[ 1 \] NAME "VIVALDI" SIZE 0,-30
DEFINE FONT aFont1\[ 2 \] NAME "Verdana" SIZE 0,-20
WITH OBJECT oBrw:Name
:aDataFont := aFont1
:aClrText := { CLR\_HBLUE, CLR\_HRED }
END
Example: image cropped in circular shape
WITH OBJECT oBrw:aCols\[ 3 \]
:bStrImage := { || "c:\\\\images\\\\photo.jpg" }
:aImgRect := { nil, 0.3, 0.7, nil, "CIRCLE" }
// nil \= full edge, 0.3 \= 30% from left, 0.7 \= 70% from left
END
14\. Inheritance — Derived Classes from TXBrowse
It is possible to create classes derived from TXBrowse and TXBrwColumn to customize behavior at the class level, automatically applying changes to all browses of the same type.
14.1 Creating a derived class from TXBrowse
CLASS MyBrowse FROM TXBrowse
CLASSDATA lRegistered AS LOGICAL // MANDATORY
DATA bColClass INIT { || MyXBrCol() } // own column class
METHOD New( oWnd ) CONSTRUCTOR
ENDCLASS
METHOD New( oWnd ) CLASS MyBrowse
Super:New( oWnd )
::nMarqueeStyle := MARQSTYLE\_HIGHLROWMS
::bClrStd := { || { CLR\_BLACK, RGB(255,255,206) } }
::bClrSelFocus := { || { CLR\_WHITE, CLR\_BLUE } }
::bClrRowFocus := { || { CLR\_BLACK, RGB(150,231,255) } }
return Self
14.2 Derived class from TXBrwColumn
CLASS MyXbrCol FROM TXBrwColumn
METHOD Adjust()
ENDCLASS
METHOD Adjust() CLASS MyXBrCol
if ::cDataType \== 'D'
::cEditPicture := 'dd-mmm-yyyy'
endif
Super:Adjust()
return Self
14.3 Activating the derived class
| Property / Event | Type | Description and Usage |
| CLASS MyBrowse() in command | Clause | @ X,Y XBROWSE oBrw CLASS MyBrowse() ... — only that browse uses the class |
| SET XBROWSE TO MyBrowse() | Command | All browses created from here use MyBrowse() |
| SET XBROWSE TO bXBr | Command | Restores the previous class (saved with SAVE PREVIOUS TO bXBr) |
| SetXBrowse({ | | MyBrowse() }) | Function | Programmatic equivalent of SET XBROWSE TO |
| lRegistered | CLASSDATA | MANDATORY in derived classes. Declares the class as registered in FWH |
| bColClass | DATA | Block that instantiates the column class. INIT { | | TXBrwColumn() } by default |
| cDataType | String | Column data type: 'C', 'N', 'D', 'L', 'M', 'F' (image) |
Example with SAVE PREVIOUS
SET XBROWSE TO MyBrowse() SAVE PREVIOUS TO bXBr
// ... create browses that will use MyBrowse ...
SET XBROWSE TO bXBr // restore original class
15\. Group Totals (SetGroupTotal)
In addition to group headers, it is possible to show automatic totals per group and a consolidated grand total.
| Property / Event | Type | Description and Usage |
| SetGroupTotal(cGrp, cHdr) | Method | Adds a total row for a group. cGrp \= group name, cHdr \= header text |
| SetGroupTotal(aGrps, cHdr, nAggr, oFont) | Method | Grand total of multiple groups. nAggr \= AGGR\_SUM (default) |
| nFooterTypes | Numeric | Aggregate type for ALL numeric columns at once |
| RefreshFooters() | Method | Refreshes all column footers |
| bOnChange | Block | Column event when value changes. { | | oBrw:MakeTotals(), oBrw:RefreshFooters()} |
| lAllowColReGroup | Logical | Allows moving columns between groups. Ex: := .T. |
Complete example
:SetGroupHeader( 'Americas', 2, 3, oBold )
:SetGroupHeader( 'Europe', 4, 5, oBold )
:lAllowColReGroup := .T.
:SetGroupTotal( 'Americas', 'Total' )
:SetGroupTotal( 'Europe', 'Total' )
:SetGroupTotal( { 'Americas\_Total', 'Europe\_Total' }, 'Grand' \+ CRLF \+ 'Total', AGGR\_SUM, oBold )
AEval( oBrw:aCols, { |o| o:bOnChange := { || oBrw:MakeTotals(), oBrw:RefreshFooters() } }, 2 )
16\. Cell Movement Control (nMoveType)
The nMoveType property controls how the cursor moves when pressing Enter or Tab after editing a cell.
| Property / Event | Type | Description and Usage |
| nMoveType | Numeric | Movement direction when confirming edit. See MOVE\_\* constants |
| MOVE\_RIGHT | Constant | Moves cursor to the right cell (default for editing) |
| MOVE\_LEFT | Constant | Moves cursor to the left cell |
| MOVE\_UP | Constant | Moves cursor to the cell above |
| MOVE\_DOWN | Constant | Moves cursor to the cell below |
| MOVE\_NONE | Constant | Does not move cursor when confirming |
| MOVE\_FAST\_RIGHT | Constant | Same as MOVE\_RIGHT but with fast behavior |
| MOVE\_FAST\_LEFT | Constant | Same as MOVE\_LEFT but with fast behavior |
| nRowSel | Numeric | Currently selected row number (visible) |
| nColSel | Numeric | Currently selected column number |
| lColChangeNotify | Logical | If .T., fires bChange also when changing columns |
| lRelyOnKeyNo | Logical | If .F., uses physical position instead of KeyNo for positioning |
Example
oBrw:nMoveType := MOVE\_RIGHT // on confirm, go right
// or dynamically:
oBrw:nMoveType := MOVE\_DOWN // spreadsheet-style behavior
17\. Additional Properties and Advanced Techniques
17.1 Text Highlighting (FW\_SayTextHilite)
Allows highlighting specific words within cell text with a different font and color, using bPaintText.
oBrw:aCols\[ 2 \]:bPaintText := {|oCol, hDC, cText, aRect, aColors|
FW\_SayTextHilite( hDC, cText, aRect, oFont, aColors\[1\], aColors\[2\],
{ { AllTrim(cWordHL), oBold, CLR\_HRED, CLR\_HGREEN } } )
return nil
}
📌 NOTE: FW\_SayTextHilite takes an array of {cWord, oFont, nTextClr, nBkgClr} for each word to highlight.
17.2 DropFile — Dragging files onto the browse
| Property / Event | Type | Description and Usage |
| DropFile(nRow, nCol, cFile) | Method | Handles dropping a file onto a specific browse cell |
| lCanPaste | Logical | Enables the paste option (Ctrl+V) in the browse. Ex: oBrw:lCanPaste := .T. |
17.3 Source Code Generation (PrgCode)
| Property / Event | Type | Description and Usage |
| PrgCode() | Method | Generates the PRG source code of the current browse. Returns array of 4 elements with different styles |
| RptCode() | Method (column) | Generates report code for the column |
| cCol | String | Original field name of the column (for code generation) |
17.4 Navigation Methods (bGoTop, bGoBottom, bSkip)
| Property / Event | Type | Description and Usage |
| bGoTop | Block | Block to go to the first record. Ex: := { | | ::nArrayAt := 1 } |
| bGoBottom | Block | Block to go to the last record |
| bSkip | Block | Block to skip N records. Receives nSkip, returns records actually skipped |
| bEof | Block | Block that indicates end of data. Ex: := { | | ::nArrayAt \> ::nRows } |
| bKeyCount | Block | Block that returns total records. Ex: := { | | ::nRows } |
| bKeyNo | Block | Block to get/set the current position (KeyNo) |
| bBookMark | Block | Block to get/set the current record bookmark |
| GoLeft(), GoRight() | Methods | Navigate to left/right column. Overridable in derived classes |
| GoUp(\[n\]), GoDown(\[n\]) | Methods | Navigate rows up/down. Overridable |
| GetDisplayColsWidth() | Method | Returns total width of visible columns |
| BrwWidth() | Method | Returns the width of the browse data area |
| aCellCoor() | Method | Returns coordinates {nTop,nLeft,nBottom,nRight} of active cell |
| SetHScroll(l) | Method | Shows/hides horizontal scrollbar. Returns the new state |
| lAdjusted | Logical | Indicates if CreateFromCode() has already been called (.T. after creation) |
18\. Progress Bars in Cells (SetProgBar)
XBrowse allows displaying a progress bar directly within a numeric cell, visualizing the value as a percentage of a given maximum. Ideal for dashboards and queued processes.
| Property / Event | Type | Description and Usage |
| SetProgBar(uMax, nHeight, bClr) | Method (col) | Activates progress bar. uMax=max value (number or block), nHeight=bar height (nil=auto), bClr=block {nFill, nBack} |
| uMax as block | Block | { | | nMaxSal } — maximum is dynamically recalculated on each paint |
| uMax as number | Numeric | 100 — fixed percentage, cell value taken as % of 100 |
| RefreshCurrent() | Method | Refreshes only current row. Much more efficient than Refresh() in ongoing processes |
| Cargo | Various | General-purpose property. Ex: oBrw:Cargo := .F. for cancellation signal |
| bClrSel | Block | Selected row color without focus. := :bClrSelFocus to equalize both states |
| lDisplayZeros | Logical | If .F., cells with value 0 are displayed empty. Useful at start of progress bars |
19\. Advanced Painting (bPaintRow / bPaintHeader / bPaintFooter)
XBrowse exposes painting hooks at the row, header, and full footer level, allowing full visual control using GDI.
19.1 bPaintRow — Painting complete rows
| Property / Event | Type | Description and Usage |
| bPaintRow | Block | { | brw,nRow,nCol,nHt,lHL,lSel,nRowPos,nColSel,oColSel | ... } — row painting hook |
| Return .T. | Logical | If returns .T., XBrowse does not paint that row (the block painted it completely) |
| Return .F. | Logical | If returns .F., XBrowse will paint normally over the block's work |
| GetDC() | Method | Gets the Device Context of the browse for GDI drawing |
| ReleaseDC() | Method | Releases the DC obtained with GetDC() |
| SayText(cText,aRect,cAlign,oFont,nClr) | Method | Draws text with the internal browse DC |
| ReadImage(cFile) | Method | Loads image from file. Returns handle |
| DrawImage(aBmp, aRect) | Method | Draws an image in the indicated rectangle |
| lDrawBorder | Logical | If .T., draws border around the browse |
| nColorBox | Numeric | Marquee border color. Ex: oBrw:nColorBox := CLR\_HRED |
| lHoverSelect | Logical | If .T., selects the record when hovering the mouse (without clicking) |
| AddVar(cName, xVal) | Method | Adds variable accessible within blocks as ::cName |
| oFont | Object | Browse font. Accessible from TDataRow: oRow:oBrw:oFont |
19.2 bPaintHeader and bPaintFooter
| Property / Event | Type | Description and Usage |
| bPaintHeader | Block | { | brw,hDC,aCols,nLast,hWPen,hGPen,hCPen | BrwHeader(...) } — paints the complete header |
| bPaintFooter | Block | { | brw,hDC,aCols,nLast,nGridW,nBrwH,hWPen,hGPen | BrwFooter(...) } — paints the complete footer |
| oCol:PaintHeader(nRow,nil,nHt,lSel,hDC) | Method (col) | Paints standard header of ONE column within the custom hook |
| oCol:PaintFooter(nRow,nil,nHt) | Method (col) | Paints standard footer of ONE column |
| oCol:PaintData(nRow,nil,nHt,lHL,lSel,n,nPos) | Method (col) | Paints data cell of ONE column — useful in bPaintRow |
| oCol:nDisplayCol | Numeric | Left X position of the column (px from browse left edge) |
| lAllowColSwapping | Logical | If .F., prevents reordering columns by dragging the header |
20\. Advanced Editing
20.1 EDIT\_BUTTON — Custom popup editor
| Property / Event | Type | Description and Usage |
| nEditType := EDIT\_BUTTON | Constant (col) | Shows button in cell when entering edit mode |
| bEditBlock | Block (col) | { | nRow, nCol, oCol | EditFunc(nRow,nCol,oCol) } — invoked on button click |
| bOnPostEdit | Block (col) | { | oCol, xVal, nKey | ... } — post-edit. xVal=new value, nKey=confirm key |
| EDIT\_LISTBOX | Constant (col) | Shows a drop-down listbox as cell editor |
| aEditListTxt | Array (col) | Items for EDIT\_LISTBOX: { {1,'one',10}, {2,'two',20} } |
| nLbxAt | Numeric (col) | Index of current selection in aEditListTxt (read-only useful in bOnChange) |
| bClrEdit | Block (col) | Edit color for ONE column: { | | { CLR\_BLACK, CLR\_YELLOW } } |
| bClrEdits | Block (browse) | Edit color for ALL browse columns |
| bOnChange | Block (col) | Executed when value changes during editing of that column |
| bOnChanges | Block (browse) | Executed when any column changes. Global for the entire browse |
20.2 CurrentRow() — Editing in independent dialog
| Property / Event | Type | Description and Usage |
| CurrentRow() | Method | Returns TDataRow object of the current row. Fields accessible as oRow:First, oRow:Salary |
| oRow:Modified() | Method | Returns .T. if there are unsaved changes |
| oRow:Save() | Method | Saves TDataRow changes to the original source |
| oRow:Undo() | Method | Discards pending changes |
| oRow:oBrw | Object | Reference to the parent browse. Ex: oRow:oBrw:oFont, oRow:oBrw:Age:cEditPicture |
| ON DBLCLICK | Clause | @ X,Y XBROWSE ... ON DBLCLICK RowEdit( oBrw:CurrentRow() ) |
| DATABASE oObj | Command | Creates a TDatabase object from the active area |
| SelectCol(nPos, lCenter) | Method | Moves focus to column. lCenter=.T. centers the column in view |
21\. Sort Combo (oSortCbx / cSortOrder)
XBrowse can be automatically linked to an external ComboBox so the user can change the display order without additional code.
| Property / Event | Type | Description and Usage |
| oSortCbx | Object | Reference to an external ComboBox. XBrowse fills it with available indexes and changes order on selection |
| cSortOrder | String | Name of the active order. Can be bound to the ComboBox VAR |
| AUTOSORT | Clause | Enables sorting by clicking on the column header |
| nColorBox | Numeric | Selection box color (MARQSTYLE\_SOLIDCELL style). Ex: CLR\_HRED |
| cHeaders | Array | Array of headers assigned via code. Ex: oBrw:cHeaders := { "Name", "Last Name" } |
| lExcelCellWise | Logical | If .T., the Excel export maintains cell-by-cell structure |
22\. Swapping Browses, SetRDD and TPages
22.1 Showing/hiding alternate browses
| Property / Event | Type | Description and Usage |
| Hide() | Method | Hides the browse without destroying it |
| Show() | Method | Shows a hidden browse |
| Enable() | Method | Enables the browse for user interaction |
| Disable() | Method | Disables the browse (no keyboard/mouse response) |
| SetRDD() | Method | Changes the RDD data source to the active area at that moment. Ex: Customer-\>( oBrw:SetRDD() ) |
| REDEFINE XBROWSE | Command | Links browse from a resource to an object. Ex: REDEFINE XBROWSE oBrw ID 10 OF oDlg |
Example: swap with tabs
aBrw\[1\]:CreateFromCode() ; aBrw\[2\]:CreateFromCode()
aBrw\[2\]:Hide() // hide at start
static function ChangeBrw( nNew, nOld, aBrw )
aBrw\[ nOld \]:Hide()
aBrw\[ nNew \]:oWnd:oClient := aBrw\[ nNew \]
aBrw\[ nNew \]:Enable() ; aBrw\[ nNew \]:Show() ; aBrw\[ nNew \]:oWnd:Resize()
return nil
22.2 Browse as page selector (TPages)
@ 10,20 XBROWSE oXBrw DATASOURCE { "First", "Second" } AUTOCOLS HEADERS "Page" NOBORDER
oXBrw:bChange := { || oPages:SetOption( oXBrw:BookMark ) }
oXBrw:CreateFromCode()
oPages := TPages():New( 10, 200, 380, 580, oDlg )
23\. Gradient in Selected Rows
XBrowse supports gradient arrays in selection color blocks, creating Office/Vista-style visual effects.
| Property / Event | Type | Description and Usage |
| bClrSelFocus with aGrad | Block | { | | { CLR\_BLACK, aSelGrad } } — gradient in focused row |
| bClrRowFocus with aGrad | Block | { | | { CLR\_BLACK, aRowGrad } } — gradient in visible rows without focus |
| aRowGrad (example) | Array | { {.5, RGB(232,241,252), RGB(232,241,252)}, {.5, RGB(210,225,244), RGB(235,243,253)} } |
| aSelGrad (example) | Array | { {.5, RGB(255,255,251), RGB(255,237,178)}, {.5, RGB(255,218,103), RGB(255,233,162)} } |
24\. Advanced Images — Image \+ Text and SetColsAsRows
24.1 Image and text in the same cell
| Property / Event | Type | Description and Usage |
| aImgRect := { nil,nil,-40,nil } | Array | Reserves 40px at the bottom for text. The image occupies the rest |
| aImgRect := "CIRCLE" | String | Circular-shaped image centered in cell |
| aImgRect := "ELLIPSE" | String | Elliptical-shaped image |
| nCellHeight | Numeric (col) | Height dedicated to this cell within a multiline row (with SetColsAsRows) |
| SetColsAsRows(aColNos) | Method (col) | Stacks columns in the same visual cell in separate rows. Ex: :SetColsAsRows( {2,3} ) |
| oDataFont | Object (col) | Font for the data text of an individual column |
| nDataStrAlign := AL\_TOP | Numeric | Aligns text to the top of cell |
| nDataStrAlign := AL\_BOTTOM | Numeric | Aligns text to the bottom (useful with image above) |
25\. Miscellaneous: UTF-8, Excel, Synchronized DBF Structure
25.1 UTF-8 Support
| Property / Event | Type | Description and Usage |
| UTF8TOUTF16(field) | Expression | Converts UTF-8 text to UTF-16 for correct display in XBrowse |
| lExcelCellWise | Logical | oBrw:lExcelCellWise := .T. — cell-by-cell Excel export |
| SetFont(oFont) | Method | Assigns Unicode font to the browse. Ex: "Segoe UI" for Unicode languages |
| nWidths as number | Numeric | oBrw:nWidths := 230 — same width for all columns |
25.2 Excel sheet browse (oRange)
oRange := GetExcelRange( cFile, "Customers", "A1:E12" )
@ 0,0 XBROWSE oBrw OF oWnd AUTOCOLS DATASOURCE oRange CELL LINES FOOTERS
oBrw:Sales:bFooter := { || oRange:Application:WorkSheetFunction:Sum( oRange:Columns(5) ) }
26\. Insertable Dynamic Subtotals (Array)
It is possible to insert subtotal rows within an array browse, calculated via blocks that are automatically re-evaluated when the user edits data.
| Property / Event | Type | Description and Usage |
| IsTotalRow(aRow) | Own function | Detects if current row is a subtotal. Ex: Empty( aRow\[1\] ) → is total row |
| bEditWhen | Block (col) | { | | \!IsTotalRow( oBrw:aRow ) } — disables editing in subtotal rows |
| bSumCondition | Block (col) | { | n,o | \!IsTotalRow( o:oBrw:aRow ) } — excludes subtotal rows from footer total |
| bEditValue with block | Block (col) | If array value is a block ('{ | | ...}'), it is evaluated with XEval(). Useful for dynamic subtotals |
| MakeSumBlock(aData,nCol,nFrom,nLast) | Own function | Creates a block { | | FW\_ArrSum(...) } that dynamically sums the indicated range |
| AIns(aData, nPos, xVal, .T.) | Function | Inserts an element at position nPos of the array, shifting others |
| FW\_ArrSum(aData, nCol) | FWH Function | Sums the values of column nCol from array aData |
27\. Transparent Watermark (bPaintBack / lTransparent)
XBrowse allows drawing an image as a semi-transparent watermark behind the data, using the bPaintBack hook and the lTransparent property.
| Property / Event | Type | Description and Usage |
| lTransparent | Logical | If .T., the browse uses transparent background (bPaintBack hook controls the background) |
| bPaintBack | Block | { | Self | ... } — background painting hook. Self \= the browse. Must paint background and maintain lTransparent := .T. |
| hDC | Handle (internal) | ::hDC — browse Device Context accessible inside bPaintBack |
| oBrush:hBrush | Handle | ::oBrush:hBrush — browse background brush handle |
| DataRect():aRect | Array | Browse data area rectangle. Useful for scaling the watermark image |
| DrawImage(aImage, aRect, nil, nil, nAlpha) | Method | Draws image with alpha transparency level (0=opaque, 255=invisible). Ex: nAlpha=64 |
| oWnd:ReadImage(cFile,,lAlpha) | Method | Reads image with alpha support (.T.). Returns handle for use with DrawImage |
| PalBmpFree(aImage) | Function | Frees memory of image loaded with ReadImage |
28\. Advanced XBROWSER: CALC, Internal Buttons and SETUP
The XBROWSER command has additional options for displaying quick-start browses with extended functionality.
| Property / Event | Type | Description and Usage |
| XBROWSER aData CALC | Command | Opens XBROWSER with a built-in editable spreadsheet (calculator mode) |
| XBROWSER aData COLUMNS {1,2,3} | Command | Shows only the indicated columns |
| XBROWSER ... SETUP codeblock | Command | Executes a code block after creating the browse. oBrw available as variable |
| BUTTON\_PRINT | Constant | Index of the print button in the XBROWSER bar. oBrw:oWnd:aControls\[BUTTON\_PRINT\] |
| BUTTON\_SHEET | Constant | Index of the sheet/export button in the XBROWSER bar |
| oBtn:cCaption | String | Changes the button text |
| oBtn:bAction | Block | Changes the button action |
29\. Exporting Selected Records to Excel (aSelected)
XBrowse allows exporting to Excel only a subset of records by specifying an array of record numbers in the aSelected property before calling ToExcel().
| Property / Event | Type | Description and Usage |
| aSelected | Array | Array of RecNos to export. Ex: oBrw:aSelected := { 10, 25, 30 }. Must be cleared after ToExcel() |
| ToExcel() | Method | Exports browse data to Excel. If aSelected is not empty, exports only those records |
| DBEVAL(bBlock, bCond) | Function | Traverses records of the active area evaluating bBlock only when bCond is .T. |
| cAlias | String | Alias of the RDD data source of the browse. Ex: (oBrw:cAlias)-\>( DBEVAL(...) ) |
Example: export only records from State X
// 1\. Build array of RecNos that meet the condition
local aRecNo := {}
local bCondi := { || (oBrw:cAlias)-\>STATE \== cState }
(oBrw:cAlias)-\>( DBEVAL( { || AAdd( aRecNo, RECNO() ) }, bCondi ) )
// 2\. Position on first matching record and refresh
(oBrw:cAlias)-\>( DBSeek( cState, .T. ) )
oBrw:Refresh()
// 3\. Assign, export and clear
oBrw:aSelected := aRecNo
oBrw:ToExcel()
oBrw:aSelected := {}
Appendix A — Complete Reference Examples
This section contains complete, functional examples extracted directly from the FiveWin/XBrowse example files. They are the most direct reference for implementing each feature.
A.1 Basic browse with RDD, editing and footer (testxbr3.prg)
\#include 'fivewin.ch'
\#include 'xbrowse.ch'
USE CUSTOMER NEW ALIAS CUST SHARED VIA "DBFCDX"
SET ORDER TO TAG FIRST
GO TOP
DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-12
DEFINE DIALOG oDlg SIZE 700,400 PIXEL FONT oFont TITLE "XBrowse RDD"
@ 10,10 XBROWSE oBrw SIZE \-10,-10 PIXEL OF oDlg ;
DATASOURCE "CUST" AUTOCOLS AUTOSORT ;
CELL LINES NOBORDER FOOTERS
WITH OBJECT oBrw
:nEditTypes := EDIT\_GET
:Married:SetCheck()
:Salary:nFooterType := AGGR\_SUM
:nStretchCol := STRETCHCOL\_WIDEST
:MakeTotals()
:CreateFromCode()
END
ACTIVATE DIALOG oDlg CENTERED ON INIT ( CUST-\>(dbGoTop()), oBrw:SetFocus(), .F. )
A.2 Array browse with internal button bar (xbrbar.prg)
@ 20,20 XBROWSE oBrw SIZE \-20,200 PIXEL OF oDlg ;
DATASOURCE "STATES" AUTOCOLS CELL LINES NOBORDER
oBrw:nTopBarHeight := 30
oBrw:bOnAdjust := \<||
@ 05,05 BTNBMP oBtn FILE "new.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:EditSource( .T. ) TOOLTIP "Add"
@ 05,45 BTNBMP oBtn FILE "edit.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:EditSource() TOOLTIP "Edit"
@ 05,85 BTNBMP oBtn FILE "delete.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
ACTION oBrw:Delete() TOOLTIP "Delete"
return nil
\>
oBrw:nEditTypes := EDIT\_GET
oBrw:CreateFromCode()
A.3 Record selector with row number and popup (xbrecsel.prg)
WITH OBJECT oBrw
:nHeaderHeight := 60
:SetChecks()
:bRecSelData := { |brw| brw:KeyNo }
:bRecSelFooter := { |brw| brw:nLen }
:bRecSelHeader := "SlNo"
:bRecSelClick := { || RecSelPopUp( oBrw ) }
:nRecSelWidth := "9999"
:AutoFit()
:CreateFromCode()
END
A.4 Group totals with grand total (xbgrpsum.prg)
WITH OBJECT oBrw
:SetGroupHeader( 'Americas', 2, 3, oBold )
:SetGroupHeader( 'Europe', 4, 5, oBold )
:lAllowColReGroup := .T.
:SetGroupTotal( 'Americas', 'Total' )
:SetGroupTotal( 'Europe', 'Total' )
:SetGroupTotal( { 'Americas\_Total', 'Europe\_Total' }, 'Grand' \+ CRLF \+ 'Total', AGGR\_SUM, oBold )
END
AEval( oBrw:aCols, { |o|
o:cEditPicture := '99,999.99'
o:nFooterType := AGGR\_SUM
o:bOnChange := { || oBrw:MakeTotals(), oBrw:RefreshFooters() } }, 2 )
oBrw:MakeTotals()
oBrw:CreateFromCode()
A.5 Incremental filter with wildcard (xbincflt.prg)
WITH OBJECT oBrw
:lIncrFilter := .T.
:lSeekWild := .T. // search 'contains'
:cFilterFld := "FIRST"
:nStretchCol := STRETCHCOL\_WIDEST
END
@ 10,10 COMBOBOX oBrw:cFilterFld ITEMS aHdrs ;
ON CHANGE ( oBrw:Seek(""), oBrw:SetFocus() )
@ 10,70 COMBOBOX nWild ITEMS { "Starts with", "Contains" } ;
ON CHANGE ( oBrw:lSeekWild := (nWild==2), oBrw:Seek(""), oBrw:SetFocus() )
A.6 Dynamic progress bars with cancellation (xbrprogd.prg)
WITH OBJECT oBrw:aCols\[ 2 \]
:SetProgBar( 100,, { || { RGB(161,224,255), CLR\_WHITE } } )
:cEditPicture := "999.99 %"
:bClrSel := :bClrSelFocus := oBrw:bClrStd
END
oBrw:lDisplayZeros := .F.
oBrw:nStretchCol := 2
oBrw:CreateFromCode()
// Process with row-by-row update:
for n := 1 to oBrw:nLen
nTotal := HB\_RandomInt( 100, 2000 )
oBrw:aArrayData\[ n, 4 \] := nTotal
oBrw:RefreshCurrent()
for i := 1 to nTotal STEP 10
SysWait( 0.01 )
oBrw:nArrayAt := n
oBrw:aArrayData\[ n, 2 \] := i / nTotal \* 100
oBrw:aArrayData\[ n, 3 \] := i
oBrw:RefreshCurrent()
if oBrw:Cargo \== .F. ; EXIT ; endif
next
if oBrw:Cargo \== .F. ; EXIT ; endif
next
A.7 Watermark with alpha PNG image (xbwaterm.prg)
aImage := oWnd:ReadImage( "c:\\\\fwh\\\\bitmaps\\\\pngs\\\\logo.png",, .T. ) // .T. \= with alpha
@ 20,20 XBROWSE oBrw ... DATASOURCE "CUSTOMER" AUTOCOLS NOBORDER CELL LINES
WITH OBJECT oBrw
:lTransparent := .T.
:bPaintBack := { |Self|
FillRect( ::hDC, GetClientRect(::hWnd), ::oBrush:hBrush )
::DrawImage( aImage, ::DataRect():aRect, nil, nil, 64 ) // 64 \= 25% opaque
::lTransparent := .T.
return nil }
:CreateFromCode()
END
// When done:
PalBmpFree( aImage )
A.8 Dynamic subtotals in array (xbsubtot.prg)
// Subtotal rows: aRow\[1\] empty \= is subtotal
oBrw:bClrStd := { || { CLR\_BLACK, If( Empty(oBrw:aRow\[1\]), CLR\_YELLOW, CLR\_WHITE ) } }
WITH OBJECT oBrw:aCols\[ nCol \]
:bEditValue := { |x,o| If( x==nil .or. ValType(oBrw:aRow\[o:nArrayCol\])=='B',
XEval( oBrw:aRow\[o:nArrayCol\] ),
oBrw:aRow\[o:nArrayCol\] := x ) }
:bEditWhen := { || \!Empty( oBrw:aRow\[1\] ) }
:bSumCondition := { |n,o| \!Empty( o:oBrw:aRow\[1\] ) }
:bOnChange := { || oBrw:Refresh() }
:nFooterType := AGGR\_SUM
END
// Insert the subtotal row:
AIns( oBrw:aArrayData, nRowLast+1, Array(Len(oBrw:aRow)), .T. )
oBrw:aArrayData\[nRowLast+1, nCol\] := { || FW\_ArrSum( aRows, nCol ) } // dynamic block
A.9 Export filtered records to Excel (xbxlsel.prg)
// Build array of RecNos meeting the condition
local aRecNo := {}
(oBrw:cAlias)-\>( DBEVAL( { AAdd( aRecNo, RECNO() ) }, { STATE \== cState } ) )
(oBrw:cAlias)-\>( DBSeek( cState, .T. ) )
oBrw:Refresh()
// Export only those records
oBrw:aSelected := aRecNo
oBrw:ToExcel()
oBrw:aSelected := {}
A.10 Derived class with column and own behavior (xbrchild.prg)
CLASS MyBrowse FROM TXBrowse
CLASSDATA lRegistered AS LOGICAL
DATA bColClass INIT { || MyXBrCol() }
METHOD New( oWnd ) CONSTRUCTOR
ENDCLASS
METHOD New( oWnd ) CLASS MyBrowse
Super:New( oWnd )
::nMarqueeStyle := MARQSTYLE\_HIGHLROWMS
::bClrStd := { || { CLR\_BLACK, RGB(255,255,206) } }
::bClrSelFocus := { || { CLR\_WHITE, CLR\_BLUE } }
::bClrRowFocus := { || { CLR\_BLACK, RGB(150,231,255) } }
return Self
CLASS MyXbrCol FROM TXBrwColumn
METHOD Adjust()
ENDCLASS
METHOD Adjust() CLASS MyXBrCol
if ::cDataType \== 'D'
::cEditPicture := 'dd-mmm-yyyy'
endif
Super:Adjust()
return Self
// Specific use:
@ 10,10 XBROWSE oBrw CLASS MyBrowse() OF oDlg ALIAS 'SALES' AUTOCOLS SIZE 200,70 PIXEL
// Global use:
SET XBROWSE TO MyBrowse() SAVE PREVIOUS TO bXBr