Same code written for one datasource can be used without any changes (or with very minimal changes in some complex cases) for the same table from another datasource/database. Writing the code in this manner makes it easy to switch database for the same software.
This is a simple sample, which browses "states" table with add and edit dialogs and delete record features.
This program may be copied to fwh\samples folder and built with buildh.bat or buildx.bat
Program Code:
Part-1 :
function Main(): Select the datasource (database)
function OpenData() --> uTable: Open the table depending on the database selected
function CloseData( uTable ): Close the table and database
Obviously, these functions are different for different databases.
- Code: Select all Expand view RUN
#include "fivewin.ch"
REQUEST DBFCDX
static oCn, nDataType
//----------------------------------------------------------------------------//
function Main()
local uTable
SET DELETED ON
SetGetColorFocus()
nDataType := Alert( "Choose Data Source", { "DBF", "TDataBase", "FWMariaDB", "ADO", "Dolphin" } )
if nDataType == 0
return nil
endif
if !Empty( uTable := OpenTable() )
BrowseTable( uTable )
CloseData( uTable )
endif
return nil
//----------------------------------------------------------------------------//
static function OpenTable()
local uTable
SWITCH nDataType
CASE 1 // DBF
USE STATES NEW SHARED VIA "DBFCDX"
uTable := ALIAS()
EXIT
case 2 // TDatabase
uTable := TDatabase():Open( nil, "STATES", "DBFCDX", .T. )
if !uTable:Used()
uTable := nil
endif
EXIT
case 3 // FWMariaDB
oCn := FW_DemoDB()
uTable := oCn:RowSet( "states" )
EXIT
case 4 // ADO
oCn := FW_DemoDB( "ADO" )
uTable := FW_OpenRecordSet( oCn, "states" )
EXIT
case 5 // DOLPHIN
#ifdef __XHARBOUR__
? "Dolphin Library not linked."
#else
oCn := FW_DemoDB( "DLP" )
uTable := oCn:Query( "SELECT * FROM states" )
#endif
EXIT
END
return uTable
//----------------------------------------------------------------------------//
static function CloseData( uTable )
SWITCH nDataType
CASE 1 // DBF
CLOSE STATES
EXIT
case 2 // TDatabase
uTable:Close()
EXIT
case 3 // FWMariaDB
uTable:Close()
EXIT
case 4 // ADO
uTable:Close()
oCn:Close()
EXIT
case 5 // DOLPHIN
#ifndef __XHARBOUR__
uTable:End()
oCn:End()
#endif
EXIT
END
oCn := nil
return nil
//----------------------------------------------------------------------------//
#ifndef __XHARBOUR__
EXTERNAL TDOLPHINSRV
#endif
Part-2:
function BrowseTable( uTable )
function EditRecord( oRecord )
These two functions are identical for all kinds of databases. The same code works for all.
We recommend this approach for any database.
These functions can be treated as a template.
- Code: Select all Expand view RUN
static function BrowseTable( uTable )
local oDlg, oBar, oFont, oBrw
DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14
DEFINE DIALOG oDlg SIZE 360,600 PIXEL TRUEPIXEL FONT oFont
DEFINE BUTTONBAR oBar OF oDlg SIZE 56,32 2010
DEFINE BUTTON OF oBar PROMPT "Add" ACTION oBrw:EditSource( .t. )
DEFINE BUTTON OF oBar PROMPT "Edit" ACTION oBrw:EditSource()
DEFINE BUTTON OF oBar PROMPT "Delete" ACTION ;
If( MsgNoYes( "Delete " + Trim( oBrw:Name:Value ) + " ?" ), ;
oBrw:Delete(), nil )
DEFINE BUTTON OF oBar PROMPT "Close" ACTION oDlg:End() BTNRIGHT
@ 60,20 XBROWSE oBrw SIZE -20,-20 PIXEL OF oDlg ;
DATASOURCE uTable ;
COLUMNS "CODE","NAME" ;
PICTURES "!!" ;
FASTEDIT CELL LINES NOBORDER
WITH OBJECT oBrw
:nStretchCol := 2
:nEditTypes := EDIT_GET
:Code:bEditValid := { |oGet| Len( Trim( oGet:VarGet() ) ) == 2 }
:Name:bEditValid := { |oGet| If( Empty( oGet:VarGet() ), oBrw:ShowMessage( "Can not be empty" ), .t. ) }
// To use custom dialog. If ommitted, FWH uses default dialog
:bEdit := { |oRec| EditRecord( oRec ) }
//
:CreateFromCode()
END
ACTIVATE DIALOG oDlg CENTERED
RELEASE FONT oFont
return nil
//----------------------------------------------------------------------------//
function EditRecord( oRec )
local lNew := ( oRec:RecNo == 0 )
local oDlg, oFont, oBtn
DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14
DEFINE DIALOG oDlg SIZE 400,240 PIXEL TRUEPIXEL FONT oFont ;
TITLE "STATES"
@ 20, 20 SAY If( oRec:RecNo == 0, "ADD NEW STATE", "EDIT STATE" ) ;
SIZE 360,22 PIXEL OF oDlg CENTER VCENTER
oDlg:bInit := <||
@ 80, 40 SAY "StateCode :" GET oRec:Code PICTURE "!!" SIZE 130,24 PIXEL OF oDlg ;
VALID If( Len( Trim( oRec:Code ) ) < 2, ( MsgAlert( "Enter 2 chars" ), .f. ), .t. )
@ 110, 40 SAY "StateName :" GET oRec:Name SIZE 300,24 PIXEL OF oDlg ;
VALID If( Empty( oRec:Name ), ( MsgAlert( "Can not be empty" ), .f. ), .t. )
return nil
>
oRec:bValid := { || Len( Trim( oRec:Code ) ) == 2 .and. !Empty( oRec:Name ) }
@ 180, 20 BTNBMP oBtn PROMPT "SAVE" SIZE 100,30 PIXEL OF oDlg FLAT ;
WHEN oRec:lValid() .and. oRec:Modified() ;
ACTION ( oRec:Save(), oDlg:End() )
@ 180,280 BTNBMP oBtn PROMPT "CANCEL" SIZE 100,30 PIXEL OF oDlg FLAT ACTION oDlg:End()
oBtn:lCancel := .t.
ACTIVATE DIALOG oDlg CENTERED ;
ON PAINT oDlg:Box( 60, 20, 155, 380 )
RELEASE FONT oFont
return nil