Many programmers know how to auto append blank rows using oBrw:bPastEof. Care should also be taken that new blank rows are not created when already a blank row created is not yet committed and if the user leaves the blank row, it should be removed. The programming code required for this is a bit complex.
Yet all this is possible only if the data-source being browsed supports this feature. Examples are Arrays, RecordSets opened with adLockBatchOptimistic lock.
FWH RowSet supports this feature. Not only it supports but also takes away totally the burden of writing this complex code. What all required to have a fast edit browse with safe auto-append facility is :
- Code: Select all Expand view RUN
oRs := oCn:RowSet( cTable/cSql )
oRs:lAutoAppend := .t.
XBROWSER oRs FASTEDIT
It is ready.
We can turn oRs:lAutoAppend ON only when we create a browse with autoappend and turn off at other times.
fwh\samples\maria09.prg (FWH 16.09) demonstrates this feature. The program is reproduced below.
In addition to auto-append feature, this program also demonstrates other features that are usually required in similar situations.
1) Case: With FWHMYSQL, we can specify if a field should have only UPPER CASE or lower case or Proper Case either at database level or at program level. When this feature is enabled, without using any picture clause for Gets, whatever be the case in which the user enters data, the data is converted to the required case while storing in the database. (The automatic case conversion is done only for pure ansi-strings and follow the (x)Harbour CodePage setting.)
2) Using default values at database level. The values are automatically refreshed in the browse when data is saved.
3) Default Values at program-level: When we use auto-append feature, we also require some columns to have default values which can not be modified by the user. The program demonstrates how to set default values at runtime when required.
Syntax: oRs:SetDefault( cFieldName, uDefaultValue, [lReadOnly = .t.] )
When read-only attribute is set, xbrowse, datarow do not allow user entry and even the rowset does not accept any modification by user.
4) Calculated Fields: From MySql server version 5.7 onwards it is possible to have calculated fields in the database.
5) Browse totals: Most such cases of browses require totals and need to be updated with every modification and appending.
maria09.prg
- Code: Select all Expand view RUN
#include "fivewin.ch"
static cHost := "localhost"
static cUser := "gnrao"
static cPassword := "secret"
static cDb := "fwh"
//----------------------------------------------------------------------------//
function Main()
local oRs
local cTable := "testauto"
local nDocID
SetGetColorFocus()
FWNumFormat( 'A', .t. )
// Check and create table
if .not. db():TableExists( cTable ) .or. ;
MsgYesNo( "ReCreate " + cTable )
if db():TableExists( cTable )
db():DropTable( cTable )
endif
if .not. db():CreateTable( cTable, { ;
{ "docid", 'N', 4, 0 }, ;
{ "code", 'C', 2, 0, "comment 'case:upper'" }, ;
{ "name", 'C', 20, 0, "comment 'case:proper'" }, ;
{ "qty", 'N', 6, 3, "DEFAULT 1" }, ;
{ "rate", 'N', 5, 2, "DEFAULT 10" }, ;
{ "amount=qty*rate", 'N', 12, 2 } }, ;
.t., "latin1" )
? "Table create error"
return nil
endif
endif
// end: Create table
// Main code starts
nDocID := 4302 // id in parent table
oRs := db():RowSet( "SELECT * FROM `testauto` WHERE `docid` = ?", { nDocID } )
oRs:lAutoAppend := .t. // Only one line of code to enable auto append feature
oRs:SetDefault( "docid", nDocID ) // All rows should contain this value
/*
* Later to use the same RowSet for another DocID,
* oRs:ReQuery( { nOtherDocID } )
* oRs:SetDefault( "docid", nOtherDocID )
*
*/
XBROWSER oRs FASTEDIT TITLE "FWH-ROWSET : AutoAppend" SETUP SetUpBrowse( oBrw )
db():Close()
return nil
//----------------------------------------------------------------------------//
static function SetupBrowse( oBrw )
WITH OBJECT oBrw
// separate color for row being appended
:bClrRowFocus := { || If( oBrw:oDbf:ID == 0, { CLR_BLACK, 0xAEEDFF }, { CLR_BLACK, RGB(185,220,255) } ) }
// Display total in footers
:lFooter := .t.
:qty:nFooterType := AGGR_SUM
:Amount:nFooterType := AGGR_SUM
:MakeTotals()
// Show some message on blank screen
:bPainted := { |dc,ps,brw| If( brw:nLen == 0, brw:SayText( "Press Down Arrow to Start" ), nil ) }
END
return nil
return nil
//----------------------------------------------------------------------------//
function db()
static oCn
if oCn == nil
EDITVARS cHost, cUser, cPassword, cDB
FWCONNECT oCn HOST cHost USER cUser PASSWORD cPassword DATABASE cDb
if oCn == nil
? "Connect Fail"
QUIT
endif
endif
return oCn
//----------------------------------------------------------------------------//
As the functionality of this sample can not be demonstrated with screen-shot, a video is provided.
Video Link
http://autode.sk/2er5ghp