TSBrowse is one of the greatest free contributions to the FiveWin community by Maestro Manuel Mercado. Many programmers like me used and were benefited by his valuable contributions. We can not forget Heranan's WBrowse too.
I consider it to be not in a good taste to compare FWH's classes with non-FWH libraries. I confine my discusssions to FWH's own browses.
Purpose of these two lines
- Code: Select all Expand view
PREEDIT { | uVar| nTotal : = nToatl - uVar } ; // Before editing
POSTEDIT {| uVar | nTotal : = nToatl + uVar } // After editing
is to update the totals by reducing the old value before edit and adding the new value after edit and then redisplay the totals. We write similar code for every column. If instead of just totals, we need to display average, std, etc. the code we need to write to recompute and display the footers is more complex.
In the case of XBrowse all this code is not required and is rather redundant.
We just need to tell xbrowse that we need totals of the column. XBrowse undestands that if a cell is edited, the total in the footer also is to be recomputed and xbrowse itself does the recomputation and refreshes display of the total.
Let us start with a simple example, where we display numeric columns, with totals in the footers and update to totals in the footers when the user edits a cell.
- Code: Select all Expand view
#include "FiveWin.Ch"
#include "ord.ch"
#include "xbrowse.ch"
//----------------------------------------------------------------------------//
REQUEST DBFCDX
//----------------------------------------------------------------------------//
function Main()
local oDlg, oBrw, oFont
USE CUSTOMER NEW ALIAS CUST SHARED
SET ORDER TO TAG FIRST
GO TOP
DEFINE FONT oFont NAME 'TAHOMA' SIZE 0,-12
DEFINE DIALOG oDlg SIZE 600,400 PIXEL TITLE 'XBrowse Totals' ;
FONT oFont
@ 10,10 XBROWSE oBrw SIZE -10,-30 PIXEL OF oDlg ;
COLUMNS "First", "Married", "HireDate", "Age", "Salary" ;
DATASOURCE "CUST" ;
AUTOSORT CELL LINES FOOTERS NOBORDER FASTEDIT
WITH OBJECT oBrw
// Specific to columns
:Married:SetCheck()
:HireDate:cEditPicture := "dd mmm yyyy"
:Age:nFooterType := AGGR_STD
:Salary:nFooterType := AGGR_SUM
// for the entire browse
:nEditTypes := EDIT_GET
:nStretchCol := STRETCHCOL_WIDEST
// finally
:MakeTotals()
:CreateFromCode()
END
@ oDlg:nHeight / 2 - 25, 10 BUTTON "Excel" SIZE 40,12 PIXEL OF oDlg ACTION oBrw:ToExcel()
@ oDlg:nHeight / 2 - 25, 55 BUTTON "Excel" SIZE 40,12 PIXEL OF oDlg ACTION oBrw:Report()
ACTIVATE DIALOG oDlg CENTERED
RELEASE FONT oFont
CLOSE CUST
return (0)
//----------------------------------------------------------------------------//
init procedure PrgInit
SET DATE ITALIAN
SET CENTURY ON
SET TIME FORMAT TO "HH:MM:SS"
SET EPOCH TO YEAR(DATE())-50
SET DELETED ON
SET EXCLUSIVE OFF
RDDSETDEFAULT( "DBFCDX" )
XbrNumFormat( 'E', .t. )
SetGetColorFocus()
return
//----------------------------------------------------------------------------//
I have used the customer.dbf in the \fwh\samples folder. Compile, link and run the program in the samples folder.
Footers display Standard Deviation of "Age" column and Total of "Salary" column. When a cell is edited, the footers are also updated automatically. Imagine the kind of code needed for all this and see how much reduction of code is possible with xbrowse, in particular, with regards to recomputation of Standard Deviation.
Let us now go through the code line by line:
- Code: Select all Expand view
XbrNumFormat( 'E', .t. ) // European number format with thousand separators.
This is the code at the beginning of the application. XBrowse automatically supplies picture clauses depending on the data type. The above setting at the outset instructs the xbrowse to use european number formatting with thousand separators by default. If we need to change the foratting to international ( American ) we simiply change this line to XBrNumFormat( 'A', .t. ). We do not need to change the picture clauses through out our application.
- Code: Select all Expand view
@ 10,10 XBROWSE oBrw SIZE -10,-30 PIXEL OF oDlg <clauses>
XBrowse provides syntaxes similar to both TWBrowse and TCBrowse. In the above line, negative sizes indicate that a margin of 10 pixels on the right and 30 pixels at the bottom to be left. We can also specify the size in absolute pixels. Advantage of specifying right and bottom margins is that if we later change the size of the dialog, we do not have to change the size of XBrowse also. In addition, if the browse is created in a window, the browse also is resized when the window is resized, without our having to write "ON RESIZE oWnd" code.
- Code: Select all Expand view
COLUMNS "First", "Married", "HireDate", "Age", "Salary" ;
XBrowse supports the legacy syntax of FIELDS ... But columns syntax is extremely powerful.
By using the above syntax, XBrowse decides a few things automatically.
XBrowse knows that it needs to display the fields with the names given above. It also knows the the programmer expects the headers to be shown in mixed case as specified. It knows that we naturally want text to be aligned left and dates and numbers to right and aligns accordingly by default. It also provides picture clauses suitable to the datatype. Dates are shown in Set Date format, and Salary is shown in european number format with thousand separators. XBrowse also computes the exact widths required to display the columns based on the field lengths. Please note that we can always override these defaults, but most of the times, these defaults serve the purpose without our having to write the code.
- Code: Select all Expand view
AUTOSORT
With this one clause, we tell XBrowse that we want that if the user clicks on header, the browse should be sorted on that column. XBrowse checks all the index tag expressions and decides the right Tag to set order to for each column. XBrowse also builds an appropriate Seek Codebolock for incremental seek on the sorted column. Incremental seeks can be on text, numbers or dates. With earlier browses, we have to write a lot of code to accomplish this.
- Code: Select all Expand view
WITH OBJECT oBrw
// Specific to columns
:Married:SetCheck()
<Other Clauses>
END
oBrw:Married returns the column object with header "Married" (Case insensitive, ignoring any blanks in the header). There are several ways to access a column object.
oBrw:aCols[ <n> ] --> Column object of <n>th column. This is the most familiar way of referring to column objects, from our experience with other browses. While we can access a column object like this, this is highly undesirable. With XBrowse the user can move the columns at the run time resulting in reordering of the columns. At runtime. oBrw:aCols[ 2 ] may not refer the second column at the time of cration of the browse.
If we prefer to use numbers, it is better to use oBrw:oCol( <n> ). This returns the <n>th column at the time of creation. However, we need to keep in mind that the column creation order can change after using any of oBrw:DelCol( <x> ). oBrw:ReArrangeCols(...) or oBrw:RestoreState(...)/
Another and safer way is to refer a column is to refer it by its header.
oBrw:oCol( cHeader ) or oBrw:cHeader returns the column object with that header.
Now by calling SetCheck() method, the logical values are displayed with on and off bitmaps. We can supply our own bitmaps or XBrowse provides default bitmaps.
- Code: Select all Expand view
:HireDate:cEditPicture := "dd mmm yyyy"
By default, xBrwose uses Set Date format for display of dates. We can override this by using a different format like the above. This new format is used while exporting to Excel or printing a report.
- Code: Select all Expand view
:Age:nFooterType := AGGR_STD
:Salary:nFooterType := AGGR_SUM
Here we instruct xbrowse that we want to show Standard Deviation in the footer of the column "Age" and totals for the column "Salary". We need to call the method oBrw:MakeTotals() once at the beginnning. Later, when a cell is edited inline XBrowse automatically recomputes the footers and repaints the footers. XBrowse does these computations incrementally for the changes alone without recalculating for the entire table again. This feature reduces lot of coding in our application program and we even do not have to know how to compute aggregates like STD.
Other aggregate functions available for footers are MIN,MAX,AVG,COUNT,STDEVP. The computations are identical to Excel's functions with the same names. When we use xBrowse's built in export to excel, xbrowse incorporate the appropriate excel formulae while exporting but not just the numbers. You may test this by exporting to excel and examining the formulae at the end.
- Code: Select all Expand view
:nEditTypes := EDIT_GET
When we create the XBrowse with the above command syntax, XBrowe creates all the columns and their codeblocks suitable for inline editing appropriate locking for shared tables. But does not allow edit by default, unless the programmer specifies a column to be editable. This can be done by oCol:nEditType := EDIT_GET (or other modes of editing). Also if we use the syntax ADD COLUMN TO oBrw .. we can use the EDITABLE clause.
We can set the editable property by setting for each column with oCol:nEditType := nEditType or for the all columns of browse at once with oBrw:nEditTypes := <nEditType].
XBrowse takes care of locking records of the DBF while saving the edited values and we do not have to write the code to save the edited values.
By default post edit navigation of cursor in FastEdit mode is similar to Excel, which we can override.
As I said earlier, recomputation of aggregates is automatic.
- Code: Select all Expand view
:nStretchCol := STRETCHCOL_WIDEST
We are used to stretch the last column with the earlier browses. But imagine how ackward it would be to streatch a numeric column like Age or Salary? It gives a better appearance by streatching a text column, preferably the widest one. XBrowse provides a great flexibility here.
There are a lot more advanced feaures built into xbrowse and it is not possible to introduce all of them in one sample like this.
XBrowse can do almost all things that can be done with earlier browses and a lot more. One difference is that XBrowse does most of these things automatically while we need to write long lines of code ourselves in earlier browses.
Now, let us again look back at preedit, postedit functionality. There may be cases where the automatic features of xbrowse are not adequate or suitable in some situations. In such a case, we can use oCol:bOnChange := { |oCol,uOldValue| OurFunc( oCol, uOldValue). This codeblock is evaluated by XBrowse when the inline edit "changes" the value of a cell. Not called when the values are same before and after edit. We can access the new value with oCol:Value and the old value is provided as the second parameter.
XBrowse is a new paradigm in browsing. Let us not compare. Just use it and enjoy great functionality with minimal coding effort.
As I keep advising, move away from the legacy way of creating XBrowse and columns as in oBrw := TXBrowse():New(), oBrw:AddCol(), oCol:bStrData, etc. This is the surest way of telling XBrowse that I dont want to use your capabilities.