|
I have a mover listbox container in which the lists can be quite large, with 400 items or more. I couldn't get satisfactory speed with arrays, but cursors worked fine except for <Add all>. I was able to get <Add all> to work faster by using two cursors and taking advantage of the native VFP DELETE/RECALL behavior with SET DELETED ON. Here are the modifications I made: 1) Create cursors in the Form.DataEnvironment.Init() or Form.Load() * create cursors for CIP Mover
SELECT SUBSTR(rv_cip.cip,1,5)+' '+rv_cip.acronym AS
CIPAcronym ;
FROM rv_cip INTO CURSOR cip_temp
SELECT cip_temp
=AFIELDS(laFields)
CREATE CURSOR t_CIPAvail FROM ARRAY laFields
CREATE CURSOR t_CIPSelect FROM ARRAY laFields
SELECT t_CIPAvail
APPEND FROM DBF('cip_temp')
*delete all
SELECT t_CIPSelect
APPEND FROM DBF('cip_temp')
delete all
USE IN cip_temp
2) Set ctrMover properties icavailablecursorname = t_CIPAvail icselectedcursorname = t_CIPSelect lstAvailable.RowSourceType = 2 lstAvailable.RowSource = "t_CIPAvail.CIPAcronym" lstAvailable.Name = "lstAvailable" lstSelected.RowSourceType = 2 lstSelected.RowSource = "t_CIPSelect.CIPAcronym" lstSelected.MoverBars = .F. lstSelected.Name = "lstSelected" 3) Add code to ctrMover.PreAddAction(), RETURNing .F. to prevent the default AddAction() * Default VMFP AddAction() is not performed when
* PreAddAction() returns .F. This code is intended to
* override the default VMFP action and applies to
* cursors only.
LOCAL llLockScreenHere, llAnySelected
llLockScreenHere = THISFORM.LockScreenHere()
WITH THISFORM.pgfrsbase1.page1.ctrrsmover1
SET DELETED OFF
FOR lnLoopCount = 1 TO .lstAvailable.LISTCOUNT
IF .lstAvailable.SELECTED(lnLoopCount)
*
* For each lstAvailable item that is selected, DELETE and Deselect.
* Locate the corresponding record in the .icSelectedCursorName alias
* and recall it.
* llAnySelected = .T.
SELECT (.icAvailableCursorName)
recnum = RECNO()
DELETE
.lstAvailable.SELECTED(lnLoopCount) = .F.
SELECT (.icSelectedCursorName)
GO recnum
RECALL
ENDIF
NEXT
SET DELETED ON
IF llAnySelected
.BoundControlsInteractiveChange()
ENDIF
.ilAnyAvailableSelected = .F.
.lstSelected.REFRESH()
.lstAvailable.REFRESH()
.lstSelected.SETFOCUS()
.lstAvailable.SETFOCUS()
* .cmdAdd.REFRESH()
* .cmdAddALL.REFRESH()
* .cmdRemove.REFRESH()
* .cmdRemoveAll.REFRESH()
.REFRESH() && only refreshes lstAvailable ?
ENDWITH
THISFORM.LockScreenHere(llLockScreenHere)
RETURN .F. && DO NOT execute default cmd Action
4) Add code to ctrMover.PreAddAllAction(), RETURNing .F. to prevent the default AddAllAction() * Default VMFP AddAllAcion() action is not performed * when PreAddAllAction() returns .F. This code is * intended to override the default VMFP action and * applies to curosrs only. LOCAL llLockScreenHere llLockScreenHere = THISFORM.LockScreenHere() WITH THISFORM.pgfrsbase1.page1.ctrrsmover1 .BoundControlsInteractiveChange() SET DELETED OFF * * Recall all records in the .icSelectedCursorName alias. * DELETE and Deselect each .iclAvailableCursorName item. * SELECT (.icSelectedCursorName) RECALL ALL SELECT (.icAvailableCursorName) DELETE ALL FOR i = 1 TO .lstAvailable.LISTCOUNT .lstAvailable.SELECTED(i) = .F. NEXT SET DELETED ON .ilAnyAvailableSelected = .F. .lstSelected.REFRESH() .lstAvailable.REFRESH() .lstSelected.SETFOCUS() .lstAvailable.SETFOCUS() * .cmdAdd.REFRESH() * .cmdAddALL.REFRESH() * .cmdRemove.REFRESH() * .cmdRemoveAll.REFRESH() .REFRESH() && onll refreshes lstAvailable ? ENDWITH THISFORM.LockScreenHere(llLockScreenHere) RETURN .F. && DO NOT execute default cmd Action 5) Add code to ctrMover.PreRemoveAction(), RETURNing .F. to prevent the default RemoveAction() * Default VMFP RemoveAction() is not performed when PreRemoveAction() returns .F. * This code is intended to override the default VMFP action * and applies to curosrs only. LOCAL llLockScreenHere, llAnySelected llLockScreenHere = THISFORM.LockScreenHere() WITH THISFORM.pgfrsbase1.page1.ctrrsmover1 SET DELETED OFF FOR lnLoopCount = 1 TO .lstSelected.LISTCOUNT IF .lstSelected.SELECTED(lnLoopCount) * * For each lstSelected item that is selected, DELETE and Deselect. * Locate the corresponding record in the .icAvailableCursorName alias * and recall it. * llAnySelected = .T. SELECT (.icSelectedCursorName) recnum = RECNO() DELETE .lstSelected.SELECTED(lnLoopCount) = .F. SELECT (.icAvailableCursorName) GO recnum RECALL ENDIF NEXT SET DELETED ON IF llAnySelected .BoundControlsInteractiveChange() ENDIF .ilAnySelectedSelected = .F. .lstSelected.REFRESH() .lstAvailable.REFRESH() .lstSelected.SETFOCUS() .lstAvailable.SETFOCUS() * .cmdAdd.REFRESH() * .cmdAddALL.REFRESH() * .cmdRemove.REFRESH() * .cmdRemoveAll.REFRESH() .REFRESH() && only refreshes lstAvailable ? ENDWITH THISFORM.LockScreenHere(llLockScreenHere) RETURN .F. && DO NOT execute default cmd Action 6) Add code to ctrMover.PreRemoveAllAction(), RETURNing .F. to prevent the default RemoveAllAction() * Default VMFP RemoveAllAction() is not performed when PreRemoveAllAction() returns .F. * This code is intended to override the default VMFP action * and applies to curosrs only. LOCAL llLockScreenHere llLockScreenHere = THISFORM.LockScreenHere() WITH THISFORM.pgfrsbase1.page1.ctrrsmover1 .BoundControlsInteractiveChange() SET DELETED OFF * * Recall all records in the .icAvailableCursorName alias. * DELETE and Deselect each .icSelectedCursorName item. * SELECT (.icAvailableCursorName) RECALL ALL SELECT (.icSelectedCursorName) DELETE ALL FOR i = 1 TO .lstSelected.LISTCOUNT .lstSelected.SELECTED(i) = .F. NEXT SET DELETED ON .ilAnySelectedSelected = .F. .lstSelected.REFRESH() .lstAvailable.REFRESH() .lstSelected.SETFOCUS() .lstAvailable.SETFOCUS() * .cmdAdd.REFRESH() * .cmdAddALL.REFRESH() * .cmdRemove.REFRESH() * .cmdRemoveAll.REFRESH() .REFRESH() && only refreshes lstAvailable ? ENDWITH THISFORM.LockScreenHere(llLockScreenHere) RETURN .F. && DO NOT execute default cmd Action 7) Bypass the default UpdateMoverOnNew() code by adding a NODEFAULT nodefault
Patrick Godfrey |