Delay EditChange while the user is still typing into SLE (search string)

Public support forum for peer to peer support with related to the Visual Objects and Vulcan.NET products
jonhn
Posts: 86
Joined: Thu Feb 01, 2018 8:04 am

Delay EditChange while the user is still typing into SLE (search string)

Post by jonhn »

Hi guys,

I have a product lookup screen - the user enters some characters in a SLE and the browser is filtered to show the results in realtime.

The user can type A...B...C... backspace... backspace...C...B... (8 keypresses to process)
I want to give the user the opportunity to type a few keys before setting the scope/filter so if they type fast enough, EditChange only sees ACB as the filter string.

I want the SLE to wait until the user has stopped typing before invoking the Edit Change and subsequent browser activity.

The SLE inherits from Willies' RightSLE -
This was discussed in the forums around 2004~8 on and off, but I can't find the discussions.

Thank you. BR Jonathan.
Terry
Posts: 306
Joined: Wed Jan 03, 2018 11:58 am

Delay EditChange while the user is still typing into SLE (search string)

Post by Terry »

Jonathon

It is a long time since I looked closely at VO, so cannot give you code.

But, I suggest what you are trying to do would be better achieved by NOT trying to trigger a new filter for every keypress.

Instead, only trigger a new filter when the user has typed in an acceptable string. This means adding some conditional logic to your EditChange Event.

See if you could perhaps initialise a string (field) when focus changes to your SLE. (EditFocusChange if I remember correctly), allowing each keypress to build up the string.

Doing it your way would be quite arbitrary - the user could easily stop halfway through typing and go for a cup of tea.

Terry
ic2
Posts: 1798
Joined: Sun Feb 28, 2016 11:30 pm
Location: Holland

Delay EditChange while the user is still typing into SLE (search string)

Post by ic2 »

Hello Jonathan,

We have an auto complete for an e-mail address, with a character typed the first e-mail address matching this is displayed with all characters except the first one selected. That means when the user types the 2nd character overwriting the selected text, it will display the first e-mail address matching the first 2 typed characters, with character 3 and above selected, and so on.

I would say that moving through a bBrowser can be accomplished too. But we do not use RightSLE. If you want I can mail you the code.

If you want the user to complete a more meaningful keyword, as Terry suggests, you may prefer to use a key for that. In recent W10 updates, searching in the File Explorer starts when you press the white arrow in the blue background, which appears after 1 character was typed. I personally prefer that to the earlier Explorers, starting to fill with every keystroke, while I normally always want the opposite of what Microsoft think is good for us :)

Dick
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Delay EditChange while the user is still typing into SLE (search string)

Post by Karl-Heinz »

Hi Jonathan,

do you really need a filter ? Is there no index available ? if so, i would set a (fast) scope each time a char is added to the sle. If you really need a complex filter, i would add next to the sle e.g. a [search] pushbutton where such a filter is evaluated.

regards
Karl-Heinz
jonhn
Posts: 86
Joined: Thu Feb 01, 2018 8:04 am

Delay EditChange while the user is still typing into SLE (search string)

Post by jonhn »

Thanks for the ideas guys,

I want to wait for 300~400ms after the last keypress in the SLE before starting the setfilter/scope setting.

It is a product lookup screen - the user can type A...B...C... backspace... backspace...C...B... (8 keypresses to process)
I want to give the user the opportunity to type a few keys before setting the scope/filter so if they type fast enough, the EditChange only sees ACB as the filter string.

This search function has been working ok for 15+ years, and is usually really fast, but it starts to lag after a few searches... just trying to tidy up some loose ends to "sign off" the VO version of my app before starting the move to X# (again!)
Terry
Posts: 306
Joined: Wed Jan 03, 2018 11:58 am

Delay EditChange while the user is still typing into SLE (search string)

Post by Terry »

Jonathon

Thanks for clarrification. However, you cannot "slow things down" or "speed them up" in the manner you suggest. Within the context of a Control that is simply impossible.

Instead you must think of a different strategy:

Eg:

Firstly subscribe to the MouseDown and MouseUp events which will tell you when the user presses and releases a Key.

Then:

Initialise some buffer // Say a (field) string when focus changes to your SLE (EditFocusChange?)

Read User Input // from KeyDown event

Adjust the buffer according to pressed key // Include processing of backspaces etc so buffer records user intent

Check buffer holds "acceptable string" // Do this on the KeyUp event


Finally please remember my first sentence; whatever you code, however complex it gets, it is for the purpose of controlling underlying electronics. This will stand you in good stead for your journey into .Net

Terry
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Delay EditChange while the user is still typing into SLE (search string)

Post by Karl-Heinz »

Hi Jonathan,

i played with a timer, and that' s the result :woohoo:

Code: Select all

CLASS sleInputTimer INHERIT SingleLineEdit
PROTECT _lTimerActive AS LOGIC
PROTECT _nInterval := 400 AS DWORD 

METHOD Destroy() CLASS sleInputTimer  

	SELF:StopTimer() 	
    
   SUPER:Destroy()  
   
   RETURN NIL

METHOD Dispatch ( oEv ) CLASS sleInputTimer
LOCAL oEvent := oEv AS Event


	DO CASE 
		
	CASE oEvent:message == WM_KEYUP
		
			SELF:StartTimer()
			

	CASE oEvent:message == WM_KEYDOWN 
		
			SELF:StopTimer()
			 
			
	CASE oEvent:message == WM_KILLFOCUS 
		
			SELF:StopTimer()
			 

	CASE oEvent:message == WM_TIMER  
		
		IF IsMethod ( SELF:Owner , #OnTimer )
			
			Send ( SELF:Owner , #OnTimer , SELF:NameSym )   
			
			SELF:StopTimer()
			
		ENDIF 	
		
	ENDCASE 
	
	
	RETURN SUPER:Dispatch ( oEvent )  


METHOD SetTimerInterval ( n ) CLASS sleInputTimer

	_nInterval := n 
	
	RETURN SELF	
METHOD StartTimer() CLASS sleInputTimer 


	IF ! _lTimerActive  
		
		IF SetTimer(SELF:Handle(), 222 , _nInterval  , NULL_PTR) == 222
		
			_lTimerActive := TRUE
			 
		ENDIF	 
		
	ENDIF	 	 
	
	RETURN _lTimerActive
	
METHOD StopTimer() CLASS sleInputTimer
      
      
  	IF _lTimerActive 
  		
		IF KillTimer ( SELF:Handle() , 222 )
		 
			_lTimerActive := FALSE 
			
		ENDIF	             

  	ENDIF 		  
	
	RETURN ! _lTimerActive 
	
Additionally you need a OnTimer() owner method.

Code: Select all

METHOD OnTimer ( symControl ) CLASS <yourWindow>
LOCAL STATIC cLast AS STRING 
LOCAL cCurrent AS STRING
      
      ?
      ? "OnTimer() triggered" 
      
		
		IF symControl == #<YourSleName>
			
			cCurrent := RTrim  (  oDCSleSeek:textvalue ) 
			
			IF cCurrent != cLast 
			                                           
				? "changed value: " , cCurrent
				
				cLast := cCurrent 
				
			ENDIF	  
			
				
		ENDIF 	
		
		RETURN NIL  

regards
Karl-Heinz
User avatar
robert
Posts: 4225
Joined: Fri Aug 21, 2015 10:57 am
Location: Netherlands

Delay EditChange while the user is still typing into SLE (search string)

Post by robert »

Karl-Heinz,
Good solution. One recommendation:
Move the check for the Ontime method to the constructor and add a field:

Code: Select all

PROTECTED lOwnerHasTimer as LOGIC
And in the constructor

Code: Select all

SELF:lOwnerHasTimer := IsMethod ( SELF:Owner , #OnTimer )
And then check for field.

Code: Select all

IF SELF:lOwnerHasTimer
Explanation:

IsMethod() is a relatively expensive method (it needs to retrieve metadata). There is no need to do that more than once per control.

Robert
XSharp Development Team
The Netherlands
robert@xsharp.eu
ic2
Posts: 1798
Joined: Sun Feb 28, 2016 11:30 pm
Location: Holland

Delay EditChange while the user is still typing into SLE (search string)

Post by ic2 »

EDIT regarding my remark below):
-----------
I realized after posting this that this is necessary for how we apply it (autocomplete e-mail addresses) but you can of course just read the current content of the control, when the timer calls your "time out" method
-----------

With the timer solution you would need one class variable which keeps track of what has been typed so far. Then it should stop the previous timer, if any, and start a new one.

If a timer exceeds your 0,4 seconds it starts doing your filter job (and stops itself again).

And make sure that you adapt the typed string when a user deletes something, with code like this in the EditChange:

dwLastKey := oControl:LastKey // saved by Dispatch() of the control
DO CASE
CASE dwLastKey == KEYBACKSPACE
CASE dwLastKey == KEYDELETE
CASE dwLastKey == KEYENTER
ENDCASE


Dick
jonhn
Posts: 86
Joined: Thu Feb 01, 2018 8:04 am

Delay EditChange while the user is still typing into SLE (search string)

Post by jonhn »

Thank you Karl-Heinz! This is exactly the thing I had in my dusty memory - maybe it was as long ago as 2001 I recall you posting this in the comp.lang.clipper.VO group!
You've made my day.
Post Reply