Would be possible, maybe using arrays, create sub-groups summary and totaling some columns in a xbrowse table?
Please see below a graph example of what I am expecting to do:
[url][url=http://postimage.org/]

Regards,
George
Code: Select all | Expand
//----------------------------------------------------------------------------//Function TablaEmpleadosSubEmpresa() Local i Local oGr2_1 Local oGr3_1 Local oGr4_1 Local oFont1 Local oFont2 Local oFont3 Local oFont4 Local oMenu Local oRBar Local oBtn1_2_1 Local oBtn2_2_1 Local oBtn1_3_1 Local oBtn1_4_1 Local aRowGrad := { { .5, nRGB( 255, 255, 255 ), nRGB( 240, 240, 240 ) }, ; { .5, nRGB( 240, 240, 240 ), nRGB( 232, 232, 232 ) } } Local aSelGrad := { { .5, nRGB( 255, 255, 180 ), nRGB( 255, 237, 178 ) }, ; { .5, nRGB( 255, 218, 103 ), nRGB( 255, 233, 162 ) } } Memvar oVarGlobales Define Font oFont1 Name 'Arial' Size 0, -10 //Italic Define Font oFont2 Name 'Tahoma' Size 0, -09 Bold Define Font oFont3 Name 'Arial' Size 0, -11 Bold //Italic Define Font oFont4 Name 'Timesw New Roman' Size 0, -10 Bold //Italic MsgRun( 'Leyendo datos, espere por favor ...',, { || BuscaLosDatos() } ) oVarGlobales : oWndMain : SetMenu( MenuTablaLegajos() ) Menu oMenu PopUp _2007 MenuItem '&Todos... ' Action( .t. ) MenuItem '&Activos' Action( .t. ) MenuItem '&Licencia' Action( .t. ) MenuItem '&Baja' Action( .t. ) EndMenu Define Window oWndTree MdiChild Of oVarGlobales : oWndMain Color 0, CLR_WHITE NoSysMenu Define RibbonBar oRBar Window oWndTree Height 55 TopMargin 0 2010 Color RGB( 220, 235, 252 ) //ColorBox RGB( 218, 229, 243 ), RGB( 218, 229, 243 ) //CLR_HRED, CLR_HBLUE oRBar : nClrBoxOut := Rgb( 240, 240, 240 ) oRBar : nClrBoxIn := Rgb( 240, 240, 240 ) Add Group oGr2_1 Ribbon oRBar TO Option 1 Prompt "volcado" Width 108 Gradiant { { 0.05, CLR_WHITE, CLR_WHITE }, { 0.9, 16777215, 12961221 } } @ 003, 003 Add Button oBtn1_2_1 Prompt "" Bitmap "imagen02" Group oGr2_1 Action oBrw : Report( 'Listado de empleados por sub-empresas' ) Size 50, 25 Top Tooltip "Imprimir" @ 003, 054 Add Button oBtn2_2_1 Prompt "" Bitmap "imagen130" Group oGr2_1 Action MsgRun( "Generando listado, espere por favor ... ",, { || oBrw : ToExcel() } ) Size 50, 25 Top Tooltip "Exportar a planilla de cálculo" Add Group oGr3_1 Ribbon oRBar TO Option 1 Prompt "filtros" Width 57 Gradiant { { 0.05, CLR_WHITE, CLR_WHITE }, { 0.9, 16777215, 12961221 } } @ 003, 003 Add Button oBtn1_3_1 Prompt "" Bitmap "imagen08" Group oGr3_1 Action FiltrosPorCategorias() Size 50, 30 Popup Top Menu oMenu Tooltip 'Filtros' //@ 003, 003 Add Button oBtn1_3_1 Prompt "" Bitmap "imagen08" Group oGr3_1 Popup Menu _MenuFiltros() Action oVarCon : oWndCon : End() Size 50, 25 Top Add Group oGr4_1 Ribbon oRBar TO Option 1 Prompt "salir" Width 57 Gradiant { { 0.05, CLR_WHITE, CLR_WHITE }, { 0.9, 16777215, 12961221 } } @ 003, 003 Add Button oBtn1_4_1 Prompt "" Bitmap "imagen98" Group oGr4_1 Action oWndTree : End() Size 50, 25 Top Tooltip 'Cerrar' @ 0, 0 xBrowse oBrw Of oWndTree oBrw : SetTree( oTree, { "#8083", "folder", "go" }, { || PonMensaje() } ) Add To oBrw Data oBrw : oTreeItem : Cargo[ 01 ] Header "ESTADO" Add To oBrw Data oBrw : oTreeItem : Cargo[ 02 ] Header "CARGO" Add To oBrw Data oBrw : oTreeItem : Cargo[ 03 ] Header "Nº LEGAJO" Add To oBrw Data oBrw : oTreeItem : Cargo[ 04 ] Header "C. DESCRIP" Add To oBrw Data oBrw : oTreeItem : Cargo[ 05 ] Header "ANTIG." Add To oBrw Data oBrw : oTreeItem : Cargo[ 06 ] Header "ALTA" Add To oBrw Data oBrw : oTreeItem : Cargo[ 07 ] Header "BAJA" Add To oBrw Data oBrw : oTreeItem : Cargo[ 08 ] Header "CARACT." Add To oBrw Data oBrw : oTreeItem : Cargo[ 09 ] Header "CATEG." Add To oBrw Data oBrw : oTreeItem : Cargo[ 10 ] Header "BRUTO" Add To oBrw Data oBrw : oTreeItem : Cargo[ 11 ] Header "NETO" Add To oBrw Data oBrw : oTreeItem : Cargo[ 12 ] Header "NO REM." Add To oBrw Data oBrw : oTreeItem : Cargo[ 13 ] Header "DESC." With Object oBrw For i := 1 To Len( :aCols ) Switch i Case 1 :aCols[ i ] : oDataFont := { || If( oBrw : oTreeItem : nLevel == 1, oFont3, If( oBrw : oTreeItem : nLevel == 2 .and. oBrw : oTreeItem : cPrompt == "TOTAL", oFont2, oFont1 ) ) } :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] : nWidth := 250 Exit Case 2 :aCols[ i ] : AddResource( 'd_ver' ) :aCols[ i ] : AddResource( 'd_roj' ) :aCols[ i ] : AddResource( 'd_ama' ) :aCols[ i ] : AddResource( 'amas' ) :aCols[ i ] : bBmpData := { || BmpData( oBrw ) } :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] : nWidth := 80 Exit Case 3 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] : nWidth := 50 Exit Case 4 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER Exit Case 5 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] : nWidth := 220 Exit Case 6 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER :aCols[ i ] : nWidth := 50 Exit Case 7 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER :aCols[ i ] : nWidth := 75 Exit Case 8 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER :aCols[ i ] : nWidth := 75 Exit Case 9 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER :aCols[ i ] : nWidth := 55 Exit Case 10 :aCols[ i ] : oDataFont := oFont1 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_CENTER :aCols[ i ] : nWidth := 45 Exit Case 11 :aCols[ i ] : oDataFont := oFont4 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_RIGHT :aCols[ i ] : nWidth := 65 Exit Case 12 :aCols[ i ] : oDataFont := oFont4 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_RIGHT :aCols[ i ] : nWidth := 65 Exit Case 13 :aCols[ i ] : oDataFont := oFont4 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_RIGHT :aCols[ i ] : nWidth := 65 Exit Case 14 :aCols[ i ] : oDataFont := oFont4 :aCols[ i ] : oHeaderFont := oFont2 :aCols[ i ] :nDataStrAlign := AL_RIGHT :aCols[ i ] : nWidth := 65 Exit EndSwitch Next i :nRowHeight := 23 :nHeaderHeight := 25 :nFooterHeight := 25 :nColDividerStyle := 5 //:nRowDividerStyle := 5 :nMarqueeStyle := MARQSTYLE_HIGHLROW :nColorPen := Rgb( 225, 225, 255 ) :nRecSelColor := nRGB( 240, 240, 240 ) :bClrSel := { || { CLR_BLACK, RGB( 255, 255, 255 ) } } :bClrSelFocus := { || { CLR_BLACK, aSelGrad } } :bClrRowFocus := { || { CLR_BLACK, aRowGrad } } :bClrGrad := { | lInvert | If( !lInvert, { { 0.5, nRGB( 255, 255, 255 ), nRGB( 240, 240, 240 ) }, ; { 0.5, nRGB( 240, 240, 240 ), nRGB( 232, 232, 232 ) } },; { { 0.50, 12961221, 16777215 }, { 0.50, 16777215, 12961221 } } ) } :bClrHeader := {|| { CLR_BLUE, nRGB( 245, 245, 245 ) } } :bClrFooter := {|| { 0,16777215 } } :bRClicked := { || oBrw : ToExcel() } :bKeyDown := { | nKey | KeyArbol( nKey ) } :lFooter := .t. :lRecordSelector := .f. :lHScroll := .f. :lColDividerComplete := .t. :nStretchCol := STRETCHCOL_WIDEST :CreateFromCode() :aCols[ 1 ] : cHeader := "SUB-EMPRESA / EMPLEADO" :oWnd : bKeyDown := { | nKey | If( nKey == VK_ESCAPE, oWndTree : End(), ) } EndWith oWndTree : oClient := oBrw Activate Window oWndTree Maximized On Init( oBrw : SetFocus() ) ; Valid ( oVarGlobales : oWndMain : SetMenu( MainMenu() ), oFont1 : End(), oFont2 : End(), oFont3 : End(), oFont4 : End(), .t. ) /* Activate Window oWndTree Maximized On Paint( oWndTree : SetFont( oFont3 ), DrawText( oWndTree : hDc, 'c:\la concha de la vaca\la puta que te pario', { 100, 100, 300, 285 }, DT_PATH_ELLIPSIS ) ) */ Return Nil //----------------------------------------------------------------------------//Static Function MenuTablaLegajos() Local oMenu Menu oMenu _2007 MenuItem "&Opciones" Menu EndMenu EndMenu Return oMenu //----------------------------------------------------------------------------//Function PonMensaje() If( oBrw : oTreeItem : nLevel == 1 ) //oSay : SetText( oBrw : oTreeItem : cPrompt ) oBrw : aCols[ 1 ] : cFooter := oBrw : oTreeItem : cPrompt //oBrw : Refresh( .f. ) End Return Nil //----------------------------------------------------------------------------//Function KeyArbol( nKey ) Local oItem := oBrw : oTreeItem Switch nKey Case VK_RETURN //? oItem : Cargo[ 2 ], Valtype( oItem : Cargo[ 5 ] ) Exit EndSwitch Return 0 //----------------------------------------------------------------------------//Static Function BuscaLosDatos() Local i Local oRs Local cQuery Local nNetos Local nNoRem Local nBrutos Local nDescuen Memvar oVarGlobales Tree oTree For i := 1 To Len( oVarGlobales : aSubEmpresa ) cQuery := 'select b.nombre, a.id_legajo, a.cargo, a.estado, a.alta, a.baja, a.anti_anios, a.anti_meses, a.c_cargo, a.caracter, a.categoria, ' +; 'bruto( a.id_legajo ), neto( a.id_legajo ), noremunerativo( a.id_legajo ), descuento( a.id_legajo ) ' +; 'from legajo a, padron b ' +; 'where a.id_empleado = b.id_empleado and a.id_empresa = ' + Alltrim( Str( oVarGlobales : nCodCol ) ) +; ' and a.id_empresa1 = ' + Alltrim( Str( oVarGlobales : aSubEmpresa[ i ][ 2 ] ) ) + ' and a.estado = "NORMAL" order by b.nombre, a.id_legajo' Query( @oRs, cQuery ) nBrutos := 0 nNetos := 0 nNoRem := 0 nDescuen := 0 If( oRs : RecordCount # 0 ) _TreeItem( oVarGlobales : aSubEmpresa[ i ][ 4 ] ) : Cargo := { Space( 15 ), Space( 10 ), Space( 10 ), Space( 50 ), Space( 10 ), Space( 20 ), Space( 20 ), Space( 20 ), Space( 10 ), Space( 10 ), Space( 10 ), Space( 10 ), Space( 10 ) } Tree While( !oRs : Eof() ) If( oRs : Fields( 'estado' ) : Value # 'BAJA' ) _TreeItem( Space( 10 ) + oRs : Fields( 'nombre' ) : Value ) : Cargo := { oRs : Fields( 'estado' ) : Value,; oRs : Fields( 'cargo' ) : Value,; StrZero( oRs : Fields( 'id_legajo' ) : Value, 6 ),; oRs : Fields( 'c_cargo' ) : Value,; StrZero( oRs : Fields( 'anti_anios' ) : Value, 2 ) + '/' + StrZero( oRs : Fields( 'anti_meses' ) : Value, 2 ),; If( Valtype( oRs : Fields( 'alta' ) : Value ) == 'D', oRs : Fields( 'alta' ) : Value, CToD( '' ) ),; If( Valtype( oRs : Fields( 'baja' ) : Value ) == 'D', oRs : Fields( 'baja' ) : Value, CToD( '' ) ),; oRs : Fields( 'caracter' ) : Value,; oRs : Fields( 'categoria' ) : Value,; Transform( oRs : Fields( 'bruto( a.id_legajo )' ) : Value, '@E 999,999,999.99' ),; Transform( oRs : Fields( 'neto( a.id_legajo )' ) : Value, '@E 999,999,999.99' ),; Transform( oRs : Fields( 'noremunerativo( a.id_legajo )' ) : Value, '@E 999,999,999.99' ),; Transform( oRs : Fields( 'descuento( a.id_legajo )' ) : Value, '@E 999,999,999.99' ) } Else _TreeItem( Space( 10 ) + oRs : Fields( 'nombre' ) : Value ) : Cargo := { oRs : Fields( 'estado' ) : Value, oRs : Fields( 'cargo' ) : Value, StrZero( oRs : Fields( 'id_legajo' ) : Value, 6 ), oRs : Fields( 'c_cargo' ) : Value, StrZero( oRs : Fields( 'anti_anios' ) : Value, 2 ) + '/' + StrZero( oRs : Fields( 'anti_meses' ) : Value, 2 ), If( Valtype( oRs : Fields( 'alta' ) : Value ) == 'D', oRs : Fields( 'alta' ) : Value, CToD( '' ) ), If( Valtype( oRs : Fields( 'baja' ) : Value ) == 'D', oRs : Fields( 'baja' ) : Value, CToD( '' ) ), oRs : Fields( 'caracter' ) : Value, oRs : Fields( 'categoria' ) : Value, Transform( 0.00, '@E 999,999,999.99' ), Transform( 0.00, '@E 999,999,999.99' ), Transform( 0.00, '@E 999,999,999.99' ), Transform( 0.00, '@E 999,999,999.99' ) } End nBrutos += oRs : Fields( 'bruto( a.id_legajo )' ) : Value nNetos += oRs : Fields( 'neto( a.id_legajo )' ) : Value nNoRem += oRs : Fields( 'noremunerativo( a.id_legajo )' ) : Value nDescuen += oRs : Fields( 'descuento( a.id_legajo )' ) : Value oRs : MoveNext() Enddo _TreeItem( Space( 10 ) + 'TOTAL' ) : Cargo := { Space( 15 ), Space( 10 ), Space( 10 ), Space( 50 ), Space( 10 ), Space( 20 ), Space( 20 ), Space( 20 ), Space( 10 ), Transform( nBrutos, '@E 999,999,999.99' ), Transform( nNetos, '@E 999,999,999.99' ), Transform( nNoRem, '@E 999,999,999.99' ), Transform( nDescuen, '@E 999,999,999.99' ) } EndTree End oRs : Close() Next i EndTree Return oTree //----------------------------------------------------------------------------//Static Function BmpData() Local nBmp := 1 /*If( Empty( oBrw : oTreeItem : cargo[ 1 ] ) ) Return */ If( oBrw : oTreeItem : nLevel == 1 ) nBmp := 4 ElseIf( Alltrim( oBrw : oTreeItem : cargo[ 1 ] ) == 'NORMAL' ) nBmp := 1 ElseIf( Alltrim( oBrw : oTreeItem : cargo[ 1 ] ) == 'LICENCIA' ) nBmp := 3 ElseIf( Alltrim( oBrw : oTreeItem : cargo[ 1 ] ) == 'BAJA' ) nBmp := 2 Else nBmp := 4 End Return nBmp //-------------------------------------------------------------------------//Function BuscaElCargo( oRs ) Local oRec Local cDescrip := '' Local cQuery := "select descrip from cargos where nomencla = '" + Alltrim( oRs : Fields( 'cargo' ) : Value ) + "'" Return cDescrip Query( @oRec, cQuery ) If( oRec : RecordCount # 0 ) cDescrip := oRec : Fields( 'descrip' ) : Value End oRec : Close() Return( cDescrip ) //----------------------------------------------------------------------------//Function FiltrosPorCategorias() Return 0
Code: Select all | Expand
#include "FiveWin.Ch"#include "ord.ch"#include "xbrowse.ch"//----------------------------------------------------------------------------//REQUEST DBFCDXstatic cFwhPath := "c:\\fwh\\"//----------------------------------------------------------------------------//function Main() BrowseTree( MakeTree() )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. ) SetKinetic( .f. ) SetGetColorFocus() SetBalloon( .t. )return//----------------------------------------------------------------------------//static function MakeTree() field STATE,CODE,CITY local cPath := cFwhPath + "samples\\" local oTree, oState, oCity USE ( cPath + "STATES" ) NEW SHARED INDEX ON CODE TAG CODE TO STMP MEMORY USE ( cPath + "CUSTOMER" ) NEW ALIAS CUST SHARED INDEX ON STATE+CITY TAG STATE TO CTMP MEMORY SET RELATION TO STATE INTO STATES GO TOP TREE oTree oTree:Cargo := { "", 0, 0.00, 0 } do while ! CUST->( eof() ) TREEITEM oState PROMPT STATES->NAME CARGO { CTOD( "" ), 0, 0.00, 0 } TREE do while STATES->NAME == oState:cPrompt .and. ! CUST->( eof() ) TREEITEM oCity PROMPT CUST->CITY ; CARGO { CUST->HIREDATE, CUST->AGE, CUST->SALARY, CUST->( RECNO() ) } oState:Cargo[ 2 ] += oCity:Cargo[ 2 ] oState:Cargo[ 3 ] += oCity:Cargo[ 3 ] CUST->( DbSkip( 1 ) ) enddo TREEITEM "Sub-Total" CARGO oState:Cargo oTree:Cargo[ 2 ] += oState:Cargo[ 2 ] oTree:Cargo[ 3 ] += oState:Cargo[ 3 ] ENDTREE enddo ENDTREEreturn oTree//----------------------------------------------------------------------------//static function BrowseTree( oTree ) local oDlg, oBrw, oFont local nGrpClr := RGB(255,250,220) local nTotClr := RGB(200,255,200) DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14 DEFINE DIALOG oDlg SIZE 620,700 PIXEL FONT oFont ; TITLE "EDITABLE TREE BROWSE WITH SUBTOTALS" @ 10,10 XBROWSE oBrw SIZE -10,-10 PIXEL OF oDlg DATASOURCE oTree ; COLUMNS 1, 2, 3 ; HEADERS "State/City", "HireDate", "Number", "Salary" ; PICTURES nil, nil, nil, NumPict ( 12, 2 ) ; CELL LINES FOOTERS FASTEDIT NOBORDER WITH OBJECT oBrw :nStretchCol := 1 :lDisplayZeros := .f. :bChange := { || CUST->( DBGOTO( oBrw:oTreeItem:Cargo[ 4 ] ) ) } :bLock := { || CUST->( RLOCK() ) } :bUnLock := { || CUST->( DBUNLOCK() ) } :bClrStd := { || { CLR_BLACK, If( oBrw:oTreeItem:nLevel == 1, nGrpClr, ; If( oBrw:oTreeItem:cPrompt == "Sub-Total", nTotClr, ; CLR_WHITE ) ) } } // Bitmaps WITH OBJECT :aCols[ 1 ] :AddBitmap( { FWRArrow(), FWDArrow(), cFwhPath + "bitmaps\16x16\reset.bmp" } ) :cFooter := "GRAND TOTAL" END // When Group is closed show totals. When open show totals at bottom // Allow edit of columns and save data to DBF, update group and grand totals WITH OBJECT :aCols[ 3 ] :bEditValue := { |x| If( oBrw:oTreeItem:lOpened, 0, ; If( x == nil, oBrw:oTreeItem:Cargo[ 2 ], ; CUST->AGE := oBrw:oTreeItem:Cargo[ 2 ] := x ) ) } :nTotal := oTree:Cargo[ 2 ] // :nEditType := EDIT_GET :bEditWhen := { || oBrw:oTreeItem:nLevel > 1 .and. oBrw:oTreeItem:cPrompt != "Sub-Total" } :bOnChange := { |o,nOld| oBrw:oTreeItem:Parent():Cargo[ 2 ] += ( o:Value - nOld ), oBrw:Refresh() } END WITH OBJECT :aCols[ 4 ] :bEditValue := { |x| If( oBrw:oTreeItem:lOpened, 0, ; If( x == nil, oBrw:oTreeItem:Cargo[ 3 ], ; CUST->SALARY := oBrw:oTreeItem:Cargo[ 3 ] := x ) ) } :nTotal := oTree:Cargo[ 3 ] // :nEditType := EDIT_GET :bEditWhen := { || oBrw:oTreeItem:nLevel > 1 .and. oBrw:oTreeItem:cPrompt != "Sub-Total" } :bOnChange := { |o,nOld| oBrw:oTreeItem:Parent():Cargo[ 3 ] += ( o:Value - nOld ), oBrw:Refresh() } END // :CreateFromCode() END Eval( oBrw:bChange ) ACTIVATE DIALOG oDlg CENTERED RELEASE FONT oFontreturn nil//----------------------------------------------------------------------------//
nageswaragunupudi wrote:The screen-shot posted first can be achieved either through Tree or simple array. Tree allows the user greater flexibility of viewing the summary and/or details. (Drill-down view)
Here is a sample program using Tree. This sample uses CUSTOMER.DBF and STATES.DBF in the fwh\samples folder. Creates a Tree with States as groups and Cities as detail items. This sample assumes fwh is installed in c:\fwh\ folder. If your fwh is installed in a different folder you need to change the static variable cFwhPath to your installation path.
This sample shows:
1) Creation of tree with group totals and grand totals.
2) Browse the tree:
(a) When a group item ( State ) is collapsed, group totals are displyed in the same row.
(b) When the group item is expanded, the totals are shown at the bottom of the list.
(c) The values in columns 3 and 4 can be edited in line with fastedit
(d) When the values are edited,
(i) the group subtotals and grand totals are automatically updated
(ii) Corresponding fields in the customer.dbf are also modified.Code: Select all | Expand
#include "FiveWin.Ch"#include "ord.ch"#include "xbrowse.ch"//----------------------------------------------------------------------------//REQUEST DBFCDXstatic cFwhPath := "c:\\fwh\\"//----------------------------------------------------------------------------//function Main() BrowseTree( MakeTree() )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. ) SetKinetic( .f. ) SetGetColorFocus() SetBalloon( .t. )return//----------------------------------------------------------------------------//static function MakeTree() field STATE,CODE,CITY local cPath := cFwhPath + "samples\\" local oTree, oState, oCity USE ( cPath + "STATES" ) NEW SHARED INDEX ON CODE TAG CODE TO STMP MEMORY USE ( cPath + "CUSTOMER" ) NEW ALIAS CUST SHARED INDEX ON STATE+CITY TAG STATE TO CTMP MEMORY SET RELATION TO STATE INTO STATES GO TOP TREE oTree oTree:Cargo := { "", 0, 0.00, 0 } do while ! CUST->( eof() ) TREEITEM oState PROMPT STATES->NAME CARGO { CTOD( "" ), 0, 0.00, 0 } TREE do while STATES->NAME == oState:cPrompt .and. ! CUST->( eof() ) TREEITEM oCity PROMPT CUST->CITY ; CARGO { CUST->HIREDATE, CUST->AGE, CUST->SALARY, CUST->( RECNO() ) } oState:Cargo[ 2 ] += oCity:Cargo[ 2 ] oState:Cargo[ 3 ] += oCity:Cargo[ 3 ] CUST->( DbSkip( 1 ) ) enddo TREEITEM "Sub-Total" CARGO oState:Cargo oTree:Cargo[ 2 ] += oState:Cargo[ 2 ] oTree:Cargo[ 3 ] += oState:Cargo[ 3 ] ENDTREE enddo ENDTREEreturn oTree//----------------------------------------------------------------------------//static function BrowseTree( oTree ) local oDlg, oBrw, oFont local nGrpClr := RGB(255,250,220) local nTotClr := RGB(200,255,200) DEFINE FONT oFont NAME "TAHOMA" SIZE 0,-14 DEFINE DIALOG oDlg SIZE 620,700 PIXEL FONT oFont ; TITLE "EDITABLE TREE BROWSE WITH SUBTOTALS" @ 10,10 XBROWSE oBrw SIZE -10,-10 PIXEL OF oDlg DATASOURCE oTree ; COLUMNS 1, 2, 3 ; HEADERS "State/City", "HireDate", "Number", "Salary" ; PICTURES nil, nil, nil, NumPict ( 12, 2 ) ; CELL LINES FOOTERS FASTEDIT NOBORDER WITH OBJECT oBrw :nStretchCol := 1 :lDisplayZeros := .f. :bChange := { || CUST->( DBGOTO( oBrw:oTreeItem:Cargo[ 4 ] ) ) } :bLock := { || CUST->( RLOCK() ) } :bUnLock := { || CUST->( DBUNLOCK() ) } :bClrStd := { || { CLR_BLACK, If( oBrw:oTreeItem:nLevel == 1, nGrpClr, ; If( oBrw:oTreeItem:cPrompt == "Sub-Total", nTotClr, ; CLR_WHITE ) ) } } // Bitmaps WITH OBJECT :aCols[ 1 ] :AddBitmap( { FWRArrow(), FWDArrow(), cFwhPath + "bitmaps\16x16\reset.bmp" } ) :cFooter := "GRAND TOTAL" END // When Group is closed show totals. When open show totals at bottom // Allow edit of columns and save data to DBF, update group and grand totals WITH OBJECT :aCols[ 3 ] :bEditValue := { |x| If( oBrw:oTreeItem:lOpened, 0, ; If( x == nil, oBrw:oTreeItem:Cargo[ 2 ], ; CUST->AGE := oBrw:oTreeItem:Cargo[ 2 ] := x ) ) } :nTotal := oTree:Cargo[ 2 ] // :nEditType := EDIT_GET :bEditWhen := { || oBrw:oTreeItem:nLevel > 1 .and. oBrw:oTreeItem:cPrompt != "Sub-Total" } :bOnChange := { |o,nOld| oBrw:oTreeItem:Parent():Cargo[ 2 ] += ( o:Value - nOld ), oBrw:Refresh() } END WITH OBJECT :aCols[ 4 ] :bEditValue := { |x| If( oBrw:oTreeItem:lOpened, 0, ; If( x == nil, oBrw:oTreeItem:Cargo[ 3 ], ; CUST->SALARY := oBrw:oTreeItem:Cargo[ 3 ] := x ) ) } :nTotal := oTree:Cargo[ 3 ] // :nEditType := EDIT_GET :bEditWhen := { || oBrw:oTreeItem:nLevel > 1 .and. oBrw:oTreeItem:cPrompt != "Sub-Total" } :bOnChange := { |o,nOld| oBrw:oTreeItem:Parent():Cargo[ 3 ] += ( o:Value - nOld ), oBrw:Refresh() } END // :CreateFromCode() END Eval( oBrw:bChange ) ACTIVATE DIALOG oDlg CENTERED RELEASE FONT oFontreturn nil//----------------------------------------------------------------------------//
nageswaragunupudi wrote:Mr. Marc
I guess you want to do this with MySql databases.
That is a lot simpler than DBFs.
I posted some sample using GROUP BY and ROLLUP. Please search and look into those samples