At first it works correctly then it makes an error and I haven't found the error
if the user activates a checkbox the procedure automatically activates a panel, the one that is free and displays it and inserts the controls for searching on xbrowse
if the user deactivates a checkbox the procedure deactivates the corresponding panel (at the time of activation an array is created where the number of the panel activated for that checkbox is stored)
When the procedure deactivates a panel it scrolls through the other remaining panels without leaving a void
the error occurs when the end user reactivates a previously deactivated checkbox
Code: Select all | Expand
#include "fivewin.ch"
#include "constant.ch"
#define DLG_nColorDlg RGB(245,245,235)
#define DLG_nColortitle1 RGB(219,230,244)
#define DLG_nColortitle2 RGB(207,221,239)
#define DLG_nColorBar1 RGB(250,250,245)
#define DLG_nColorBar2 RGB(245,245,235)
#define DLG_nColorBtn1 RGB(245,245,235)
#define DLG_nColorBtn2 RGB(250,250,245)
#define DLG_nColorBtnB RGB(195,195,185)
REQUEST DBFCDX
static l2Box,l3Box,l4Box
static nBoxNumber
STATIC aCheckboxPanelMap
function Main()
local oDlg, oBrw, oFont, oBold
local nBottom := 32.4
local nRight := 95
local nHt := nBottom * DLG_CHARPIX_H
local nWd := Max(nRight * DLG_CHARPIX_W, 180)
local oBox := Array(4) // 3+1
local oDbf, oState
local nRow
local aState := {}
l2Box := .F.
l3Box := .F.
l4Box := .F.
aCheckboxPanelMap:=array(3)
oFont := TFont():New("TAHOMA", 0, 14)
oBold := TFont():New( "TAHOMA", 0, 14,,.t. )
oState := TDataBase():Open(nil, "STATES", "DBFCDX", .T.)
oState:gotop()
Do While !oState:eof()
AADD(aState, {oState:CODE, oState:NAME})
oState:skip()
enddo
oState:close()
oDbf := TDataBase():Open(nil, "CUSTOMER", "DBFCDX", .T.)
DEFINE DIALOG oDlg SIZE nWd, nHt PIXEL TRUEPIXEL;
FONT oFont COLOR CLR_BLACK, RGB(245,245,235);
STYLE nOR(DS_MODALFRAME, WS_POPUP, WS_CAPTION, WS_SYSMENU, WS_MINIMIZEBOX)
@ 40, 10 XBROWSE oBrw SIZE -10,-60 PIXEL OF oDlg;
DATASOURCE oDbf;
COLUMNS "ID", "CITY", "STATE", "MARRIED", "AGE";
CELL LINES NOBORDER UPDATE
WITH OBJECT oBrw
:nRowHeight := 25
:l2007 := .F.
:l2015 := .T.
:lRecordSelector := .F.
:nColDividerStyle := LINESTYLE_LIGHTGRAY
:nRowDividerStyle := LINESTYLE_LIGHTGRAY
:nStretchCol := STRETCHCOL_WIDEST
:nMarqueeStyle := MARQSTYLE_HIGHLROW
:SetChecks()
:lHScroll := .F.
:CreateFromCode()
END
nRow := 440
oBox[1] := PanelBox(nRow, 10, 30, oDlg:nWidth - 20, DLG_nColorBar1, DLG_nColorBar2,oDlg)
nRow -= 31
oBox[2] := PanelBox(nRow, 10, 30, oDlg:nWidth - 20, DLG_nColorBar1, DLG_nColorBar2,oDlg)
nRow -= 31
oBox[3] := PanelBox(nRow, 10, 30, oDlg:nWidth - 20, DLG_nColorBar1, DLG_nColorBar2,oDlg)
nRow -= 31
oBox[4] := PanelBox(nRow, 10, 30, oDlg:nWidth - 20,DLG_nColorBar1, DLG_nColorBar2,oDlg)
ACTIVATE DIALOG oDlg CENTERED;
ON INIT (oBox[2]:hide(), oBox[3]:hide(), oBox[4]:hide(),;
Form_Check(oBox, oDbf, oBrw, oDlg, aState))
return nil
//----------------------------------------------------------------//
Function Form_Check(oBox, oDbf, oBrw, oDlg, aState)
local cFilter := ""
local aFilters := { { .F., "AGE>20" }, { .F., "STATE='NY'" }, { .F., "MARRIED" } }
local aCheck[3], n
local nRow := 8
local nCol := 120
local oSay
@ 8, 40 SAY { || "FILTER : " + cFilter } SIZE 400, 25 PIXEL OF oDlg CENTER UPDATE TRANSPARENT
@ nRow, 5 SAY oSay PROMPT "Filter by" SIZE 80, 20 PIXEL OF oBox[1];
COLOR CLR_BLACK, Rgb(250,250,245)
oSay:lTransparent := .T.
for n := 1 to Len(aFilters)
aCheck[n] := CreateChk(nRow, nCol, oBox, aFilters, n, oDbf, @cFilter, oBrw, oDlg, aState)
aCheck[n]:lTransparent := .T.
aCheck[n]:setcolor(CLR_BLACK, rgb(210,210,205))
nCol += 160
if n == 3
EXIT
endif
next
return nil
//----------------------------------------------------------------//
static function CreateChk(nRow, nCol, oBox, aFilters, nIndex, oDbf, cFilter, oBrw, oDlg, aState)
local oChk
@ nRow, nCol CHECKBOX oChk VAR aFilters[nIndex, 1];
PROMPT aFilters[nIndex, 2] SIZE 150, 15 PIXEL OF oBox[1];
ON CHANGE (cFilter := ResetFilter(aFilters, oDbf, oBox, oBrw, aState, nIndex ), oDlg:Update())
return oChk
//----------------------------------------------------------------//
Function Refresh_Filter(oDbf, oBrw, cFilter, aFilters)
local af := {}
AEVAL(aFilters, { |a| If(a[1], AAdd(af, a[2]), nil) })
cFilter := FW_ArrayAsList(af, " .AND. ")
oDbf:SetFilter(cFilter)
oDbf:GoTop()
oBrw:Refresh()
return nil
//-----------------------------------------------------------------------------//
function PanelBox(nTop, nLeft, nBottom, nRight, nClrLite, nClrDark,oDlg)
local oPanel,oBrush
Local aGrad := { nClrLite,nClrDark}
DEFINE BRUSH oBrush GRADIENT aGrad
oPanel:=Tpanel():New( nTop, nLeft,nTop+nBottom, nRight, oDlg)
oPanel:SetBrush( oBrush )
* oPanel:bPainted := { || oPanel:Box( 1,1,oPanel:nHeight-1,oPanel:nWidth-1 ) }
return oPanel
//-----------------------------------------------------------------------------//
FUNCTION ActivateNextBox( oBox, l2Box, l3Box, l4Box, oDlgx )
local nPanel
IF l2Box
IF l3Box
IF l4Box
// All boxes are already active, do nothing
ELSE
oBox[4]:Show()
oDlgx := oBox[4]
l4Box := .T.
nPanel:= 4
ENDIF
ELSE
oBox[3]:Show()
oDlgx := oBox[3]
l3Box := .T.
nPanel:= 3
ENDIF
ELSE
oBox[2]:Show()
oDlgx := oBox[2]
l2Box := .T.
nPanel:= 2
ENDIF
RETURN nPanel
//--------------------------------------------------------------------------//
FUNCTION DeactivateBox( oBox, nIndex, l2Box, l3Box, l4Box, oDlgx )
DO CASE
CASE nIndex == 2
IF l2Box
oBox[2]:Hide()
l2Box := .F.
oDlgx := NIL
AdjustPanelPosition(oBox, 2)
ENDIF
CASE nIndex == 3
IF l3Box
oBox[3]:Hide()
l3Box := .F.
oDlgx := NIL
AdjustPanelPosition(oBox, 3)
ENDIF
CASE nIndex == 4
IF l4Box
oBox[4]:Hide()
l4Box := .F.
oDlgx := NIL
AdjustPanelPosition(oBox, 4)
ENDIF
ENDCASE
RETURN NIL
//--------------------------------------------------------------------------//
// When a checkbox activates a panel, we add the mapping to our array
FUNCTION ActivatePanel(nCheckboxIndex, nPanelIndex)
aCheckboxPanelMap[nCheckboxIndex] := nPanelIndex
RETURN NIL
//--------------------------------------------------------------------------//
// When we want to deactivate a panel, we use mapping to find the panel
FUNCTION DeactivatePanel(nCheckboxIndex, oBox,oBrw)
LOCAL nPanelIndex := aCheckboxPanelMap[nCheckboxIndex]
IF nPanelIndex != NIL
oBox[nPanelIndex]:Hide()
aCheckboxPanelMap[nCheckboxIndex] := NIL
// Spostiamo gli altri pannelli
AdjustPanelPosition(oBox,oBrw)
ENDIF
RETURN NIL
//--------------------------------------------------------------------------//
// Function to move the remaining panels when one is deactivated
FUNCTION AdjustPanelPosition(oBox, oBrw)
LOCAL nDesiredTop := 440
LOCAL nPanelHeight := 30 // Height of the single panel
LOCAL nCurrentTop := nDesiredTop
// Calculate the number of active panels
LOCAL nActivePanels := 0
FOR nIndex := 2 TO LEN(oBox)
IF !Empty(oBox[nIndex])
nActivePanels++
ENDIF
NEXT
// Calculate the new position of the active panels
IF nActivePanels > 0
nCurrentTop -= nPanelHeight * nActivePanels
ENDIF
FOR nIndex := 2 TO LEN(oBox)
IF !Empty(oBox[nIndex])
oBox[nIndex]:nTop := nCurrentTop
nCurrentTop += nPanelHeight
ENDIF
NEXT
RETURN NIL
//--------------------------------------------------------------------------//
STATIC FUNCTION ResetFilter(aFilters, oDbf, oBox, oBrw, aState, nIndex)
LOCAL cFilter := ""
LOCAL af := {}
LOCAL cState := SPACE(25)
LOCAL lMarried := .F.
LOCAL nAge := 0
LOCAL oCmb, nState := 1
LOCAL nRow := 8
LOCAL oSay, oRadio, nRadio := 1, cMarried := ""
LOCAL oDlgx, i
LOCAL aAge := {"20", "40", "60"}
LOCAL nBoxHeight := 30
LOCAL nVisibleBoxHeight := 0
LOCAL oCtrl
LOCAL nPanel
oDlgx := NIL
IF aFilters[nIndex, 1]
// We use ActivateNextBox to get the number of the activated panel
nPanel := ActivateNextBox(oBox, @l2Box, @l3Box, @l4Box, @oDlgx)
nVisibleBoxHeight := 30
// We hide the controls if they are there in oDlgx
IF !Empty(oDlgx:acontrols)
FOR EACH oCtrl IN oDlgx:acontrols
oCtrl:hide()
NEXT
ENDIF
// We activate the panel corresponding to the checkbox
ActivatePanel(nIndex, nPanel)
DO CASE
CASE nIndex == 1 // Age
@ nRow, 5 SAY oSay PROMPT "Age:" SIZE 80, 20 PIXEL OF oDlgx;
COLOR CLR_BLACK, Rgb(250,250,245)
oSay:lTransparent := .T.
@ 0.4, 10 COMBOBOX oCmb VAR nAge ITEMS aAge;
SIZE 600, 90 OF oDlgx;
ON CHANGE (cFilter := 'AGE<' + LTrim(Str(nAge)),;
aFilters[1, 2] := cFilter,;
Refresh_Filter(oDbf, oBrw, @cFilter, aFilters))
CASE nIndex == 2 // State
@ nRow, 5 SAY oSay PROMPT "State:" SIZE 80, 20 PIXEL OF oDlgx;
COLOR CLR_BLACK, Rgb(250,250,245)
oSay:lTransparent := .T.
@ 0.4, 10 COMBOBOX oCmb VAR nState ITEMS ArrTranspose(aState)[2];
SIZE 600, 90 OF oDlgx;
ON CHANGE (cState := aState[nState][1],;
cFilter := 'STATE=' + "'" + cState + "'",;
aFilters[2, 2] := cFilter,;
Refresh_Filter(oDbf, oBrw, @cFilter, aFilters))
CASE nIndex == 3 // Married
@ nRow, 5 SAY oSay PROMPT "Married:" SIZE 80, 20 PIXEL OF oDlgx;
COLOR CLR_BLACK, Rgb(250,250,245)
oSay:lTransparent := .T.
@ 1, 80 RADIO oRadio VAR nRadio OF oDlgx UPDATE SIZE 80, 25 PIXEL;
PROMPT "Married";
ON CHANGE (IF(nRadio == 1, cMarried := ".T.", cMarried := ".F."),;
cFilter := 'MARRIED=' + cMarried,;
aFilters[3, 2] := cFilter,;
Refresh_Filter(oDbf, oBrw, @cFilter, aFilters))
@ 1, 400 RADIOITEM "Not Married" RADIOMENU oRadio;
OF oDlgx PIXEL SIZE 80, 20
ENDCASE
ELSE
// We deactivate the panel corresponding to the checkbox
DeactivatePanel(nIndex, oBox,oBrw)
nVisibleBoxHeight -= 30 // Let's remove the height of the deactivated panel
ENDIF
// Let's update the smaller browser size
oBrw:nBottomMargin += nVisibleBoxHeight
// Let's update the filter and browser
AEVAL(aFilters, { |a| If(a[1], AAdd(af, a[2]), NIL) })
cFilter := FW_ArrayAsList(af, " .AND. ")
oDbf:SetFilter(cFilter)
oDbf:GoTop()
oBrw:Refresh()
RETURN cFilter
//--------------------------------------------------------------------------//