XBROWSE : INLINE EDITING
1) For each column which must be edited , add this control to your dialog with the same syntax from the other controls
oCol:bOnPostEdit can be set. If not it receives a default value (only browse is updated)
Can also be set with SetPostEdit(oBrw,Arrayindex,Fieldindex)
In your browse add a column (Logical value , set on .T.) and define a checkbox and ON CHANGE as in EditDbf (line 122)
Not tested , but a button should also be possible
2) Set oBrw:bPastEof() , oBrw:lDblClick and obrw:bKeydown (see EditDbf.prg , prg-file , line +/- 130)
3) On init hide the controls from the browse
Editing a row can be interupted with Escape
Changes are only written with the OK checkbox
That is all
Frank Demont
Notes
Fastedit mode is only activated when also oCol:nEdittype is set
From all other data used to edit the column is only bPostEdit used
- Code: Select all Expand view
# include "fivewin.ch"
# include "xbrowse.ch"
# include "Common.ch"
# include "dtpicker.ch"
# define CLR_1 nRGB( 190, 215, 190 )
# define CLR_2 nRGB( 230, 230, 230 )
FUNCTION MAIN(cDbfFile)
***********************
LOCAL aStruct , lTest := .F.
LOCAL i , j
LOCAL aCountry
LOCAL oWnd , oBmp
IF IsNil(cDbfFile)
cDbfFile := "Demo.Dbf"
lTest := .T.
END
IF ! "." IN cDbfFile
cDbfFile += ".dbf"
END
IF ! File(cDbfFile)
aStruct := {{"Name","C",25,0},{"Number","N",10,2},{"Country","C",3,0},{"Maried","L",1,0},{"Date","D",8,0}}
DbCreate(cDbfFile,aStruct)
USE (cDbfFile)
aCountry := {"BE ","NL ","FR "}
j := 1
FOR i := 1 TO 20
APPEND BLANK
REPL FIELD->Name WITH PAD("Name " + LTRIM(STR(i)),25)
REPL FIELD->Number WITH i*1000
REPL FIELD->Country WITH aCountry[j++]
REPL FIELD->Maried WITH ( i%2 == 0 )
REPL FIELD->Date WITH Date() + i
IF j > 3
j := 1
END
NEXT
USE
END
USE (cDbfFile) SHARED
DEFINE WINDOW oWnd TITLE "Edit Dbf" ;
MENU BuildMenu( oWnd ) MDI ;
MENUINFO 3
DEFINE BITMAP oBmp RESOURCE "Background"
SET MESSAGE OF oWnd TO FWVERSION + ", " + FWCOPYRIGHT CENTERED TIME DATE
oWnd:bPainted = { | hDC | BmpTiled( hDC, oWnd, oBmp ) }
ACTIVATE WINDOW oWnd
return nil
//----------------------------------------------------------------------------//
function BuildMenu( oWnd )
local oMenu
MENU oMenu
MENUITEM "Edit Dbf";
ACTION EditDbf( oWnd )
ENDMENU
return oMenu
CLOS ALL
RETURN
********************************************************************************************************************************
PROC EditDbf(oWnd)
**************
LOCAL Arr[0]
LOCAL oDlg , oBrw , oBut
LOCAL aObj[3]
LOCAL i
LOCAL el := {SPACE(25),1000,"BE ", .T. , Date() , .T. }
LOCAL aCountry := {"BE ","NL ","FR "}
LOCAL lNieuw := .F.
ReadDbfData(Arr)
DEFINE DIALOG oDlg RESOURCE "TEST" OF oWnd
oBrw := TXBrowse():New( oDlg )
//oBrw := TXBrowse():New( oWnd )
oBrw:CreateFromResource( 101 )
oBrw:nMarqueeStyle := 3 //Highlight row //MARQSTYLE_HIGHLCELL
oBrw:nColDividerStyle := LINESTYLE_BLACK
oBrw:nRowDividerStyle := LINESTYLE_BLACK
oBrw:lHScroll := .F. ////oBrw:lColDividerComplete := .t.
oBrw:bClrStd := {|| {CLR_BLACK, iif( oBrw:nArrayAt() % 2 = 0, CLR_1, CLR_2 ) } }
oBrw:bClrSelFocus := {||{CLR_WHITE, CLR_GREEN}}
oBrw:nArrayAt := 1
oBrw:nRowSel := 1
oBrw:nRowHeight := 25 //oBrw:nRowHeight*1.2
oBrw:lFastEdit := .T.
oBrw:SetArray( Arr )
FOR i := 1 TO LEN(Arr[1])
oBrw:aCols[ i ]:cHeader = Field(i)
IF IsLogical(Arr[1,i])
oBrw:aCols[ i ]:nWidth = 20
MakeBitmapCol(oBrw,i)
END
NEXT
ATAIL(oBrw:aCols):Hide()
IF ! __ObjHasData(oBrw:aCols[1],"OBRWOBJ")
__OBJADDDATA(oBrw:aCols[1],"oBrwObj")
END
__objModMethod(oBrw:aCols[1],"Edit",@ActivateoBrwDlg(oBrw , oDlg))
REDEFINE GET oBrw:aCols[1]:oBrwObj VAR el[1] ID 100 OF oDlg VALID ! EMPTY(el[1])
oBrw:aCols[ 1 ]:nEditType := 1 // Fastedit works only when set!!!
REDEFINE GET oBrw:aCols[2]:oBrwObj VAR el[2] ID 105 OF oDlg PICTURE "9999999.99"
oBrw:aCols[ 2 ]:nWidth = 80
oBrw:aCols[ 2 ]:nEditType := 1 // Fastedit !!!
REDEFINE COMBOBOX oBrw:aCols[3]:oBrwObj VAR el[3] ITEMS aCountry;
ID 110 OF oDlg
REDEFINE CHECKBOX oBrw:aCols[4]:oBrwObj VAR el[4] ID 120 OF oDlg
oBrw:aCols[ 5 ]:nWidth = 100
REDEFINE DTPICKER oBrw:aCols[5]:oBrwObj VAR el[5] ID 130 OF oDlg
oBrw:aCols[ 6 ]:cHeader = "OK"
oBrw:aCols[ 6 ]:nWidth = 38
REDEFINE CHECKBOX oBrw:aCols[6]:oBrwObj VAR el[6] ID 140 OF oDlg;
ON CHANGE {||IIF(oBrw:aCols[6]:oBrwObj:Varget(),SaveoBrwDlg(oBrw,@lNieuw,oDlg,oBut),)}
oBrw:aCols[6]:Hide()
FOR i := 1 TO FCOUNT()
SetPostEdit(oBrw,i,i)
NEXT
OBrw:bPastEof() := {|| IIF( NewoBrwDlg(oBrw , @lNieuw) , (Sysrefresh() , ActivateoBrwDlg(oBrw , oDlg)) , ) }
oBrw:bLDblClick := {||ActivateoBrwDlg(oBrw , oDlg)}
oBrw:bkeyDown := { | nkey |IIF(nkey==13 , ActivateoBrwDlg(oBrw , oDlg) , IIF(nKey==VK_DELETE , WisoBrwDlg(oBrw , @lNieuw) , ) ) }
REDEFINE BUTTON oBut ID 300 OF oDlg ACTION oDlg:End()// WHEN ! lNieuw
ACTIVATE DIALOG oDlg ;
ON INIT ( AEVAL(oBrw:aCols,{|oCol|IIF(IsObJect(oCol:oBrwObj),oCol:oBrwObj:Hide(),) }) );
VALID IIF(GETKEYSTATE(VK_ESCAPE) , ( ActivateDlg(oDlg,oBrw,oBut,@lNieuw) , .F.) , .T. )
RETURN
********************************************************************************************************************************
PROC ReadDbfData(Arr)
*********************
LOCAL b , i
GO TOP
DO WHIL ! EOF()
b := {}
FOR i := 1 TO FCOUNT()
AADD(b,Fieldget(i))
NEXT
AADD(b,.T.)
AADD(b,Recno())
AADD(Arr,b)
SKIP
END
RETURN
********************************************************************************************************************************
PROC SetPostEdit(oBrw,i,j)
**************************
// i : Arrayindex , j : Field Index
oBrw:aCols[i]:bOnPostEdit := {|o | x := o:oBrwObj:Varget() , oBrw:aArrayData[ oBrw:nArrayAt, i ] := x , IIF(IsNil(j),,FieldPut(j,x)) }
RETURN
*****************************************************************************************************
PROC MakeBitmapCol(oBrw,i)
***************************
LOCAL oCol
LOCAL x
oCol := oBrw:aCols[i]
oCol:AddResource("CHECKON")
oCol:AddResource("CHECKOFF")
x := LEN(oCol:aBitMaps)
oCol:bBmpData := {||IIF(IsLogical(oBrw:aArrayData[oBrw:nArrayAt,i]) , IIF(oBrw:aArrayData[oBrw:nArrayAt,i],x-1,x),0)}
oCol:bStrData := {||" "}
RETURN
******************************************************************************************************
FUNC NewoBrwDlg(oBrw , lNieuw )
******************************
LOCAL Arr := {}
LOCAL x
LOCAL i
IF lNieuw
RETURN .F.
END
GO 9999999 // EOF() !
Arr := {}
FOR i := 1 TO FCOUNT()
x := Fieldget(i)
IF ValType(x) = "D"
x := Date()
END
AADD(Arr , x)
NEXT
AADD(Arr,.T.) // Ok checkbox
AADD(Arr,0) // RecNr 0 , record will be appended when the ok checkbox is clicked
AADD(oBrw:aArrayData,Arr)
oBrw:GoBottom()
oBrw:Refresh()
lNieuw := .T.
RETURN .T.
*****************************************************************************
PROC WisoBrwDlg(oBrw , lNieuw)
*********************************
LOCAL Nr := oBrw:NarrayAt
LOCAL RecNr := ATAIL(oBrw:aArrayData[Nr])
DbGoto(RecNr)
IF RLOCK()
DbDelete()
DbUnlock()
aDel(oBrw:aArrayData,Nr,.T.)
oBrw:nArrayAt := MIN(Nr,LEN(oBrw:aArraydata))
oBrw:Refresh()
IF lNieuw
lNieuw := .F.
END
END
RETURN
**********************************************************
PROC SaveoBrwDlg(oBrw , lNieuw , oDlg , oBut)
**********************************************
LOCAL Nr := oBrw:nArrayAt
LOCAL RecNr := ATAIL(oBrw:aArrayData[Nr])
LOCAL oCol , i
LOCAL lOk := .F.
FOR EACH oCol IN oBrw:aCols
IF IsObject(oCol:oBrwObj) .AND. IsBlock(oCol:oBrwObj:bValid) .AND. ! EVAL(oCol:oBrwObj:bValid)
oCol:oBrwObj:SetFocus()
RETURN
END
NEXT
IF lNieuw
IF ! DBAPPEND()
RETURN
END
RecNr := RecNo()
ATAIL(oBrw:aArrayData[Nr]) := RecNr
END
DbGoto(RecNr)
FOR EACH oCol IN oBrw:aCols
IF IsObject(oCol:oBrwObj) .AND. IsBlock(oCol:bOnPostEdit)
i := Hb_EnumIndex()
EVAL(oCol:bOnPostEdit,oCol)
END
NEXT
oBrw:DrawLine(.t.)
DbCommit()
DbGoto(recnr)
lNieuw := .F.
DBUNLOCK()
ActivateDlg(oDlg,oBrw,oBut,.F.,@lNieuw)
oBrw:SetFocus()
RETURN
********************************************************************************************************************************
PROC ActivateoBrwDlg(oBrw,oDlg)
*******************************
LOCAL nRow
LOCAL nCol
lOCAL nWidth
LOCAL nHeight
LOCAL Nr //:= oBrw:nArrayAt
LOCAL nKol //:= oBrw:nColSel
LOCAL x
LOCAL oCol , i , Obj , Gehi
LOCAL RecNr
LOCAL aDisPlay
LOCAL Self := HB_QSelf() , cKey , nKey
IF ! IsNil(Self)
nKey := IIF(IsNumber(oBrw),oBrw,nil)
oBrw := Self:oBrw
oDlg := oBrw:oWnd
IF isnumber(nKey)
cKey := Chr( nKey )
END
END
Nr := oBrw:nArrayAt
nKol := oBrw:nColSel
RecNr := ATAIL(oBrw:aArraydata[Nr])
IF RecNr > 0
DbGoto(RecNr)
IF ! RLOCK()
RETURN
END
END
FOR EACH Obj IN oDlg:aControls
Obj:Disable()
NEXT
nRow := ( ( oBrw:nRowSel - 1 ) * oBrw:nRowHeight ) + oBrw:HeaderHeight() + 2 + oBrw:nTop
nHeight := oBrw:nRowHeight - 4
aDisPlay := oBrw:GetDisplayCols()
FOR EACH oCol IN oBrw:aCols
IF IsObject(oCol:oBrwObj)
i := Hb_EnumIndex()
WITH OBJECT oCol
nCol := :nDisPlayCol + 2 + oBrw:nLeft
nWidth := :nWidth - 4
x := oBrw:aArrayData[Nr,oCol:nCreationOrder]
If oCol:cHeader = "OK"
nCol := oBrw:nWidth + oBrw:nLeft + 2
x := .F.
END
IF __ObjHasMethod(:oBrwObj,"VARPUT") // BUTTON ???
:oBrwObj:Varput(x)
:oBrwObj:Refresh()
END
IF (i IN aDisplay) .OR. oCol:cHeader = "OK"
IF (i IN aDisplay) .AND. i == aDisplay[1] // Selected col (or clicked) is no edit column
Obj := :oBrwObj
Gehi := i
END
:oBrwObj:Enable()
:oBrwObj:Move(nRow, nCol, nWidth, nHeight, .t. )
:oBrwObj:Show()
IF IsNil(:bOnPostEdit)
SetPostEdit(oBrw,i)
END
IF i == nKol // Selected col (or clicked)
Obj := :oBrwObj
Gehi := i
END
END
END
END
NEXT
IF ! IsNil(Obj)
IF IsNumber(Gehi) .AND. IsNumber(nKey)
oCol := oBrw:aCols[Gehi]
If oBrw:lFastEdit .and. oBrw:nMarqueeStyle <= MARQSTYLE_HIGHLCELL .and. ;
oCol:nEditType > 0 .and. ;
( IsAlpha( cKey ) .or. IsDigit( cKey ) .or. cKey == "-" )
IF __ObjHasMethod(oCol:oBrwObj,"VARPUT") // BUTTON ???
x := oBrw:aArrayData[Nr,oCol:nCreationOrder]
IF IsCharacter(x)
oCol:oBrwObj:bGotFocus := {|self|Self:Keychar(cKey) , Self:oGet:Pos := 2 , Self:EditUpdate() , self:Setpos(2),Self:bGotFocus:=nil}
ELSEIF IsNumber(x)
IF (48<=nKey .AND. nKey <= 57) .or. cKey == "-"
oCol:oBrwObj:bGotFocus := {|self|Self:Keychar(cKey) , Self:oGet:Pos := 2 , Self:EditUpdate() , self:Setpos(2),Self:bGotFocus:=nil}
oCol:oBrwObj:lClrFocus := .T.
END
END
oCol:oBrwObj:Refresh()
END
end
END
Obj:Setfocus()
END
RETURN
********************************************************************************************************************************
PROC ActivateDlg(oDlg,oBrw,oBut,lNieuw)
***************************************
LOCAL oCol , i , Obj
LOCAL Nr
LOCAL RecNr
IF oDlg:aControls[1]:lActive // Can give problems when this contol is a oCol:oBrwObj !!!!!!!
oBut:Setfocus()
return
END
FOR EACH Obj IN oDlg:aControls
Obj:Enable()
NEXT
FOR EACH oCol IN oBrw:aCols
IF IsObject(oCol:oBrwObj)
oCol:oBrwObj:Hide()
END
NEXT
Nr := oBrw:nArrayAt
RecNr := ATAIL(oBrw:aArrayData[Nr])
IF RecNr == 0
aDel(oBrw:aArrayData,Nr,.T.)
oBrw:nLen := LEN(oBrw:aArrayData)
oBrw:nArrayAt := MIN(oBrw:nArrayAt,oBrw:nLen)
oBrw:GoBottom()
oBrw:Refresh()
lNieuw := .F.
ELSE
DbGoto(RecNr)
DbUnlock()
END
oBrw:setFocus()
RETURN
**********************************************************************************************
PROC Trace(...) // Only to test
*************
LOCAL i , el
LOCAL tkst := ""
LOCAL arr := HB_aParams() , elem , hlp
FOR EACH el IN arr
IF Valtype(el) == "A"
FOR EACH elem IN el
hlp := cValToChar(elem)
IF IsCharacter(elem) .AND. LEN(elem) == 1 .AND. ASC(elem) < 32
hlp := 'CHR('+LTRIM(STR(Asc(elem))) + ')'
END
tkst += CRLF + hlp
NEXT
ELSEIF ValType(el) == "H"
FOR i := 1 TO LEn(el)
hlp := cValToChar(el[i])
IF IsCharacter(Hlp) .AND. LEN(Hlp) == 1 .AND. ASC(Hlp) < 32
hlp := 'CHR('+LTRIM(STR(Asc(Hlp))) + ')'
END
tkst += CRLF + PAD(HaaGetKeyAt(el,i),10) + " : " + hlp
NEXT
ELSE
tkst += CRLF + cValToChar(el)
END
NEXT
i := 0
DO WHIL ! EMPTY(PROCNAME(i))
tkst += CRLF + PROCNAME(i) + " " + "Lijn : " + LTRIM(STR(PROCLINE(i)))
i++
END
? tkst
RETU
//----------------------------------------------------------------//
STATIC FUNCTION BmpTiled( hDC, oWnd, oBmp )
local nWidth := oWnd:nWidth(), nHeight := oWnd:nHeight()
local nRow := 0, nCol := 0, n
local nBmpWidth := oBmp:nWidth(), nBmpHeight := oBmp:nHeight()
if oBmp:hBitmap == 0
return nil
endif
while nRow < nHeight
nCol = 0
while nCol < nWidth
PalBmpDraw( hDC, nRow, nCol, oBmp:hBitmap )
nCol += nBmpWidth
end
nRow += nBmpHeight
end
return nil
**************************************************************
TEST DIALOG 6, 15, 450, 227
STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "TXBrowse demo"
FONT 8, "MS Sans Serif"
{
CONTROL "", 101, "TXBrowse", 0 | WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_TABSTOP, 4, 5, 328 , 202
EDITTEXT 100 , 197 , 2, 20, 10, WS_BORDER | WS_TABSTOP
EDITTEXT 105 , 197 , 2, 20, 10, WS_BORDER | WS_TABSTOP
COMBOBOX 110, 8, 16, 72, 75, CBS_DROPDOWNLIST | WS_CHILD | WS_VISIBLE | WS_TABSTOP
CHECKBOX " ", 120 , 230 , 235 , 80, 14, BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP //, 8192
CONTROL "", 130 , "SysDateTimePick32", 0 | WS_CHILD | WS_VISIBLE | WS_TABSTOP | DTS_SHOWNONE , 153, 108 , 55, 10
CHECKBOX "OK ", 140 , 230 , 235 , 32 , 14, BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP //, 8192
PUSHBUTTON "OK", 300 , 252, 211, 50, 14
}
CHECKON BITMAP "bitmap\Checkon.bmp"
CHECKOFF BITMAP "bitmap\Checkoff.bmp"
BACKGROUND BITMAP "bitmap\fiveback.bmp"