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 / EventTypeDescription and Usage
bRecSelDataBlockContent of the selector cell. {brwbrw:KeyNo} shows sequential number
bRecSelHeaderString/BlockSelector header. Ex: oBrw:bRecSelHeader := "SlNo"
bRecSelFooterString/BlockSelector footer. {brwbrw:nLen} shows total records
nRecSelWidthNumeric/StringSelector width. If string, used as model: "9999" → width for 4 digits
nRecSelHeadBmpNoNumeric/String/ArrayBitmap in selector header. Can be path, number, or line descriptor
bRecSelClickBlockClick on selector header. {RecSelPopUp(oBrw)}
SetRecSelBmp(xBmp)MethodSets custom bitmap in selector. nil=default, 0=no bitmap, cFile=image
lRecordSelectorLogicalShows/hides entire selector. Default: .T.
RecSelShowRecNo()MethodDisplays the record number in the selector (convenient shortcut)
SetChecks()MethodConfigures all logical fields as checkboxes in the browse
SetMultiSelectCol()MethodAdds automatic multi-selection checkbox column
oMultiSelColObjectReference to the multi-selection column created by SetMultiSelectCol()
SelectRow()MethodReturns .T. if the current row is selected (for use with bSumCondition)
oRightColObjectColumn frozen on the RIGHT. Ex: oBrw:oRightCol := oBrw:Salary
KeyNoNumericSequential 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 / EventTypeDescription and Usage
lGetBarLogicalActivates/deactivates the GETs bar below headers. Ex: oBrw:lGetBar := .T.
uBarGetValVariousInitial value of the column GET. Ex: oCol:uBarGetVal := Space(10)
cBarGetPicStringMask of the GET in the bar. Ex: oCol:cBarGetPic := NumPict(FieldLen(n), FieldDec(n))
bClrEditsBlockColor of bar GETs. {{CLR\_BLACK, CLR\_YELLOW}}
oHeaderFontsObjectFont for headers. Ex: oBrw:oHeaderFonts := oBold
AutoFit()MethodAutomatically adjusts column width to content
11.2 Incremental Filter
Allows filtering the browse while the user types, without needing to press Enter.
Property / EventTypeDescription and Usage
lIncrFilterLogicalActivates real-time incremental filter. Ex: oBrw:lIncrFilter := .T.
lSeekWildLogicalIf .T., filters by content (contains). If .F., filters by beginning (starts with)
cFilterFldStringName of the field to filter. Ex: oBrw:cFilterFld := "FIRST"
cSeekStringCurrent search text (read)
oSeekSAY ObjectSAY control showing current search text
Seek(cText)MethodExecutes 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 / EventTypeDescription and Usage
nTopBarHeightNumericHeight in pixels of the internal bar. Ex: oBrw:nTopBarHeight := 30
bOnAdjustBlockBlock executed when creating/adjusting the browse. Internal buttons are created here
EditSource(\[lNew\])MethodOpens 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 ;
@ 05,45 BTNBMP oBtn FILE "edit.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
@ 05,85 BTNBMP oBtn FILE "delete.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
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 / EventTypeDescription and Usage
aDataFontArray of fontsArray of font objects per line. Line N uses aDataFont\[N\]. Ex: oCols\[1\]:aDataFont := {oFont1, oFont2}
aClrTextArray of colorsArray of text colors per line. nil \= default color. Ex: {CLR\_HBLUE, CLR\_HRED}
nDataStrAlignNumericCan combine AL\_CENTER \+ AL\_BOTTOM for vertical+horizontal alignment
aImgRectArrayImage crop in cell: {nTop%, nLeft%, nBottom%, nRight%, cShape}. Shape: "CIRCLE", nil=rect
lFitGridHeightLogicalAdjusts browse height to fit exactly N complete rows
nHeadStrAlignsNumericAlignment of ALL headers at once (browse property)
nWidthsArray/NumericIf 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'
endif
Super:Adjust()
return Self
14.3 Activating the derived class
Property / EventTypeDescription and Usage
CLASS MyBrowse() in commandClause@ X,Y XBROWSE oBrw CLASS MyBrowse() ... — only that browse uses the class
SET XBROWSE TO MyBrowse()CommandAll browses created from here use MyBrowse()
SET XBROWSE TO bXBrCommandRestores the previous class (saved with SAVE PREVIOUS TO bXBr)
SetXBrowse({MyBrowse() })FunctionProgrammatic equivalent of SET XBROWSE TO
lRegisteredCLASSDATAMANDATORY in derived classes. Declares the class as registered in FWH
bColClassDATABlock that instantiates the column class. INIT {TXBrwColumn() } by default
cDataTypeStringColumn 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 / EventTypeDescription and Usage
SetGroupTotal(cGrp, cHdr)MethodAdds a total row for a group. cGrp \= group name, cHdr \= header text
SetGroupTotal(aGrps, cHdr, nAggr, oFont)MethodGrand total of multiple groups. nAggr \= AGGR\_SUM (default)
nFooterTypesNumericAggregate type for ALL numeric columns at once
RefreshFooters()MethodRefreshes all column footers
bOnChangeBlockColumn event when value changes. {oBrw:MakeTotals(), oBrw:RefreshFooters()}
lAllowColReGroupLogicalAllows 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 / EventTypeDescription and Usage
nMoveTypeNumericMovement direction when confirming edit. See MOVE\_\* constants
MOVE\_RIGHTConstantMoves cursor to the right cell (default for editing)
MOVE\_LEFTConstantMoves cursor to the left cell
MOVE\_UPConstantMoves cursor to the cell above
MOVE\_DOWNConstantMoves cursor to the cell below
MOVE\_NONEConstantDoes not move cursor when confirming
MOVE\_FAST\_RIGHTConstantSame as MOVE\_RIGHT but with fast behavior
MOVE\_FAST\_LEFTConstantSame as MOVE\_LEFT but with fast behavior
nRowSelNumericCurrently selected row number (visible)
nColSelNumericCurrently selected column number
lColChangeNotifyLogicalIf .T., fires bChange also when changing columns
lRelyOnKeyNoLogicalIf .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\],
Code: Select all | Expand
{ { 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 / EventTypeDescription and Usage
DropFile(nRow, nCol, cFile)MethodHandles dropping a file onto a specific browse cell
lCanPasteLogicalEnables the paste option (Ctrl+V) in the browse. Ex: oBrw:lCanPaste := .T.
17.3 Source Code Generation (PrgCode)
Property / EventTypeDescription and Usage
PrgCode()MethodGenerates 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
cColStringOriginal field name of the column (for code generation)
17.4 Navigation Methods (bGoTop, bGoBottom, bSkip)
Property / EventTypeDescription and Usage
bGoTopBlockBlock to go to the first record. Ex: := {::nArrayAt := 1 }
bGoBottomBlockBlock to go to the last record
bSkipBlockBlock to skip N records. Receives nSkip, returns records actually skipped
bEofBlockBlock that indicates end of data. Ex: := {::nArrayAt \> ::nRows }
bKeyCountBlockBlock that returns total records. Ex: := {::nRows }
bKeyNoBlockBlock to get/set the current position (KeyNo)
bBookMarkBlockBlock to get/set the current record bookmark
GoLeft(), GoRight()MethodsNavigate to left/right column. Overridable in derived classes
GoUp(\[n\]), GoDown(\[n\])MethodsNavigate rows up/down. Overridable
GetDisplayColsWidth()MethodReturns total width of visible columns
BrwWidth()MethodReturns the width of the browse data area
aCellCoor()MethodReturns coordinates {nTop,nLeft,nBottom,nRight} of active cell
SetHScroll(l)MethodShows/hides horizontal scrollbar. Returns the new state
lAdjustedLogicalIndicates 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 / EventTypeDescription 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 blockBlock{nMaxSal } — maximum is dynamically recalculated on each paint
uMax as numberNumeric100 — fixed percentage, cell value taken as % of 100
RefreshCurrent()MethodRefreshes only current row. Much more efficient than Refresh() in ongoing processes
CargoVariousGeneral-purpose property. Ex: oBrw:Cargo := .F. for cancellation signal
bClrSelBlockSelected row color without focus. := :bClrSelFocus to equalize both states
lDisplayZerosLogicalIf .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 / EventTypeDescription and Usage
bPaintRowBlock{brw,nRow,nCol,nHt,lHL,lSel,nRowPos,nColSel,oColSel... } — row painting hook
Return .T.LogicalIf returns .T., XBrowse does not paint that row (the block painted it completely)
Return .F.LogicalIf returns .F., XBrowse will paint normally over the block's work
GetDC()MethodGets the Device Context of the browse for GDI drawing
ReleaseDC()MethodReleases the DC obtained with GetDC()
SayText(cText,aRect,cAlign,oFont,nClr)MethodDraws text with the internal browse DC
ReadImage(cFile)MethodLoads image from file. Returns handle
DrawImage(aBmp, aRect)MethodDraws an image in the indicated rectangle
lDrawBorderLogicalIf .T., draws border around the browse
nColorBoxNumericMarquee border color. Ex: oBrw:nColorBox := CLR\_HRED
lHoverSelectLogicalIf .T., selects the record when hovering the mouse (without clicking)
AddVar(cName, xVal)MethodAdds variable accessible within blocks as ::cName
oFontObjectBrowse font. Accessible from TDataRow: oRow:oBrw:oFont
19.2 bPaintHeader and bPaintFooter
Property / EventTypeDescription and Usage
bPaintHeaderBlock{brw,hDC,aCols,nLast,hWPen,hGPen,hCPenBrwHeader(...) } — paints the complete header
bPaintFooterBlock{brw,hDC,aCols,nLast,nGridW,nBrwH,hWPen,hGPenBrwFooter(...) } — 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:nDisplayColNumericLeft X position of the column (px from browse left edge)
lAllowColSwappingLogicalIf .F., prevents reordering columns by dragging the header
20\. Advanced Editing
20.1 EDIT\_BUTTON — Custom popup editor
Property / EventTypeDescription and Usage
nEditType := EDIT\_BUTTONConstant (col)Shows button in cell when entering edit mode
bEditBlockBlock (col){nRow, nCol, oColEditFunc(nRow,nCol,oCol) } — invoked on button click
bOnPostEditBlock (col){oCol, xVal, nKey... } — post-edit. xVal=new value, nKey=confirm key
EDIT\_LISTBOXConstant (col)Shows a drop-down listbox as cell editor
aEditListTxtArray (col)Items for EDIT\_LISTBOX: { {1,'one',10}, {2,'two',20} }
nLbxAtNumeric (col)Index of current selection in aEditListTxt (read-only useful in bOnChange)
bClrEditBlock (col)Edit color for ONE column: {{ CLR\_BLACK, CLR\_YELLOW } }
bClrEditsBlock (browse)Edit color for ALL browse columns
bOnChangeBlock (col)Executed when value changes during editing of that column
bOnChangesBlock (browse)Executed when any column changes. Global for the entire browse
20.2 CurrentRow() — Editing in independent dialog
Property / EventTypeDescription and Usage
CurrentRow()MethodReturns TDataRow object of the current row. Fields accessible as oRow:First, oRow:Salary
oRow:Modified()MethodReturns .T. if there are unsaved changes
oRow:Save()MethodSaves TDataRow changes to the original source
oRow:Undo()MethodDiscards pending changes
oRow:oBrwObjectReference to the parent browse. Ex: oRow:oBrw:oFont, oRow:oBrw:Age:cEditPicture
ON DBLCLICKClause@ X,Y XBROWSE ... ON DBLCLICK RowEdit( oBrw:CurrentRow() )
DATABASE oObjCommandCreates a TDatabase object from the active area
SelectCol(nPos, lCenter)MethodMoves 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 / EventTypeDescription and Usage
oSortCbxObjectReference to an external ComboBox. XBrowse fills it with available indexes and changes order on selection
cSortOrderStringName of the active order. Can be bound to the ComboBox VAR
AUTOSORTClauseEnables sorting by clicking on the column header
nColorBoxNumericSelection box color (MARQSTYLE\_SOLIDCELL style). Ex: CLR\_HRED
cHeadersArrayArray of headers assigned via code. Ex: oBrw:cHeaders := { "Name", "Last Name" }
lExcelCellWiseLogicalIf .T., the Excel export maintains cell-by-cell structure
22\. Swapping Browses, SetRDD and TPages
22.1 Showing/hiding alternate browses
Property / EventTypeDescription and Usage
Hide()MethodHides the browse without destroying it
Show()MethodShows a hidden browse
Enable()MethodEnables the browse for user interaction
Disable()MethodDisables the browse (no keyboard/mouse response)
SetRDD()MethodChanges the RDD data source to the active area at that moment. Ex: Customer-\>( oBrw:SetRDD() )
REDEFINE XBROWSECommandLinks 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 / EventTypeDescription and Usage
bClrSelFocus with aGradBlock{{ CLR\_BLACK, aSelGrad } } — gradient in focused row
bClrRowFocus with aGradBlock{{ 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 / EventTypeDescription and Usage
aImgRect := { nil,nil,-40,nil }ArrayReserves 40px at the bottom for text. The image occupies the rest
aImgRect := "CIRCLE"StringCircular-shaped image centered in cell
aImgRect := "ELLIPSE"StringElliptical-shaped image
nCellHeightNumeric (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} )
oDataFontObject (col)Font for the data text of an individual column
nDataStrAlign := AL\_TOPNumericAligns text to the top of cell
nDataStrAlign := AL\_BOTTOMNumericAligns text to the bottom (useful with image above)
25\. Miscellaneous: UTF-8, Excel, Synchronized DBF Structure
25.1 UTF-8 Support
Property / EventTypeDescription and Usage
UTF8TOUTF16(field)ExpressionConverts UTF-8 text to UTF-16 for correct display in XBrowse
lExcelCellWiseLogicaloBrw:lExcelCellWise := .T. — cell-by-cell Excel export
SetFont(oFont)MethodAssigns Unicode font to the browse. Ex: "Segoe UI" for Unicode languages
nWidths as numberNumericoBrw: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 / EventTypeDescription and Usage
IsTotalRow(aRow)Own functionDetects if current row is a subtotal. Ex: Empty( aRow\[1\] ) → is total row
bEditWhenBlock (col){\!IsTotalRow( oBrw:aRow ) } — disables editing in subtotal rows
bSumConditionBlock (col){n,o\!IsTotalRow( o:oBrw:aRow ) } — excludes subtotal rows from footer total
bEditValue with blockBlock (col)If array value is a block ('{...}'), it is evaluated with XEval(). Useful for dynamic subtotals
MakeSumBlock(aData,nCol,nFrom,nLast)Own functionCreates a block {FW\_ArrSum(...) } that dynamically sums the indicated range
AIns(aData, nPos, xVal, .T.)FunctionInserts an element at position nPos of the array, shifting others
FW\_ArrSum(aData, nCol)FWH FunctionSums 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 / EventTypeDescription and Usage
lTransparentLogicalIf .T., the browse uses transparent background (bPaintBack hook controls the background)
bPaintBackBlock{Self... } — background painting hook. Self \= the browse. Must paint background and maintain lTransparent := .T.
hDCHandle (internal)::hDC — browse Device Context accessible inside bPaintBack
oBrush:hBrushHandle::oBrush:hBrush — browse background brush handle
DataRect():aRectArrayBrowse data area rectangle. Useful for scaling the watermark image
DrawImage(aImage, aRect, nil, nil, nAlpha)MethodDraws image with alpha transparency level (0=opaque, 255=invisible). Ex: nAlpha=64
oWnd:ReadImage(cFile,,lAlpha)MethodReads image with alpha support (.T.). Returns handle for use with DrawImage
PalBmpFree(aImage)FunctionFrees 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 / EventTypeDescription and Usage
XBROWSER aData CALCCommandOpens XBROWSER with a built-in editable spreadsheet (calculator mode)
XBROWSER aData COLUMNS {1,2,3}CommandShows only the indicated columns
XBROWSER ... SETUP codeblockCommandExecutes a code block after creating the browse. oBrw available as variable
BUTTON\_PRINTConstantIndex of the print button in the XBROWSER bar. oBrw:oWnd:aControls\[BUTTON\_PRINT\]
BUTTON\_SHEETConstantIndex of the sheet/export button in the XBROWSER bar
oBtn:cCaptionStringChanges the button text
oBtn:bActionBlockChanges 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 / EventTypeDescription and Usage
aSelectedArrayArray of RecNos to export. Ex: oBrw:aSelected := { 10, 25, 30 }. Must be cleared after ToExcel()
ToExcel()MethodExports browse data to Excel. If aSelected is not empty, exports only those records
DBEVAL(bBlock, bCond)FunctionTraverses records of the active area evaluating bBlock only when bCond is .T.
cAliasStringAlias 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 ;
@ 05,45 BTNBMP oBtn FILE "edit.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
@ 05,85 BTNBMP oBtn FILE "delete.bmp" SIZE 30,20 PIXEL OF oBrw NOBORDER ;
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
Code: Select all | Expand
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|
Code: Select all | Expand
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',
Code: Select all | Expand
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'
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