Dear José,
The key idea is the same as your TBrowse approach: skip the expensive operations while keys are still pending. In
FiveWin you can check NextKey() or peek the Windows message queue.
Simple approach: check NextKey() before refreshing
Code: Select all | Expand
CASE IsRange( nKey, 32, 127 ) .AND. cFilterKey != NIL .AND. cnSQL:RecordCount() != 0
IF Chr( nKey ) $ ['/*]
nKey := 32
ENDIF
cFilter += Upper( Chr( nKey ) )
IF ! ADOFilter( cnSQL, cFilterKey, cFilter, aADOFilterList, nADOFilterPos )
cFilter := Left( cFilter, Len( cFilter ) - 1 )
IF Len( cFilter ) == 0
cnSQL:Filter( "" )
ELSE
ADOFilter( cnSQL, cFilterKey, cFilter, aADOFilterList, nADOFilterPos )
ENDIF
ENDIF
// Update label always (cheap)
oLabel:Varput( cFilter )
oLabel:Refresh()
// Only do the expensive browse refresh if no more keys pending
IF NextKey() == 0
oBrowse:SetArray( Array( cnSQL:RecordCount() ) )
oBrowse:Refresh()
ENDIF
ENDCASE
NextKey() returns 0 when the keyboard buffer is empty - meaning the user has stopped typing, so it's worth doing the
full refresh now.
Alternative: small Inkey() wait (like your TBrowse pattern)
If NextKey() alone isn't enough (e.g. keys arrive slightly delayed), you can add a tiny wait:
Code: Select all | Expand
oLabel:Varput( cFilter )
oLabel:Refresh()
// Give a tiny window for the next keystroke to arrive
IF Inkey( 0.05 ) == 0 // 50ms, no key arrived
oBrowse:SetArray( Array( cnSQL:RecordCount() ) )
oBrowse:Refresh()
ELSE
// A key arrived - it stays in the buffer for the next iteration
// Skip the expensive refresh, the next keystroke will handle it
ENDIF
The 0.05 (50ms) is a good balance - fast enough to feel instant, long enough to catch fast typing.
Important detail
When you finally do the refresh (on the last keystroke or on Enter/click), make sure SetArray() + Refresh() always
runs. You could add a flag:
Code: Select all | Expand
LOCAL lNeedsRefresh := .F.
// Inside the CASE:
lNeedsRefresh := .T.
IF NextKey() == 0
oBrowse:SetArray( Array( cnSQL:RecordCount() ) )
oBrowse:Refresh()
lNeedsRefresh := .F.
ENDIF
// After the DO WHILE (or on Enter/Escape/Click):
IF lNeedsRefresh
oBrowse:SetArray( Array( cnSQL:RecordCount() ) )
oBrowse:Refresh()
ENDIF
This guarantees the browse is always correct when the user stops typing or takes an action, even if NextKey() skipped
some intermediate refreshes.
The NextKey() == 0 approach is the closest equivalent to your TBrowse stabilize pattern and should give you
significant speedup when typing multiple characters quickly.