Incremental Search in BROWSE

Moderator: Rathinagiri

User avatar
Clip2Mania
Posts: 95
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium
Been thanked: 1 time

Incremental Search in BROWSE

Post by Clip2Mania » Thu Jun 26, 2014 8:37 am

I would like to implement an incremental search in a BROWSE.
E.g. When typing a character, 'seek' to the first occurrence in the indexed table - when typing a second character, seeking further in the index, and so on. "Clearing" the seek-string by means of a Ctrl-Key combination.
A bit like the example GridIncrementalSearch in \SAMPLES\Controls\Grid.
Is this possible in a BROWSE ? How can I do that?

Best Regards,

User avatar
mol
Posts: 2842
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Has thanked: 119 times
Been thanked: 64 times
Contact:

Post by mol » Thu Jun 26, 2014 9:45 am

You can do it with events.
I can post you my functions, but have no time to translate it to English (code is rather "clear")
If you are interested in it, please post.

User avatar
mol
Posts: 2842
Joined: Thu Sep 11, 2008 5:31 am
Location: Myszków, Poland
Has thanked: 119 times
Been thanked: 64 times
Contact:

Post by mol » Thu Jun 26, 2014 9:57 am

a piece of code:

Code: Select all

DEFINE BROWSE B_Towary 
		parent OknoTabTowarow
        ROW    20
        COL    10
        WIDTH  900
        HEIGHT 370
        VALUE Nil
        WIDTHS aLocalWidths
        HEADERS aLocalHeaders
        WORKAREA towary
        FIELDS aLocalFields
        FONTNAME "Arial"
        FONTSIZE 9
        TOOLTIP ""
        ONCHANGE OknoSzybkaTabelaTowarow_AktualizujPodglad()
        ONGOTFOCUS Nil
        ONLOSTFOCUS Nil
        FONTBOLD .F.
        FONTITALIC .F.
        FONTUNDERLINE .F.
        FONTSTRIKEOUT .F.
        ONDBLCLICK if(JakoSlownik, OknoSzybkaTabelaTowarow_ZwrocKodTowaru(), NIL)
		MULTISELECT .F.
        ALLOWEDIT .F.
        ALLOWAPPEND .F.
        ONHEADCLICK {{||ZmienKluczTowaru(1)},{||ZmienKluczTowaru(2)},{||ZmienKluczTowaru(3)},{||ZmienKluczTowaru(4)}}
        ALLOWDELETE .F.
        HELPID Nil
        VALID Nil
        VALIDMESSAGES Nil
        LOCK Nil
        VSCROLLBAR .T.
        DYNAMICBACKCOLOR aLocalBackColors
        DYNAMICFORECOLOR Nil
        INPUTMASK Nil
        FORMAT Nil
        WHEN Nil
        INPUTITEMS Nil
        DISPLAYITEMS Nil
        BACKCOLOR NIL
        FONTCOLOR NIL
        IMAGE Nil
        JUSTIFY aLocalJust
        NOLINES .F.
        READONLYFIELDS Nil
        HEADERIMAGES Nil
    END BROWSE

define Search textbox

Code: Select all

 DEFINE TEXTBOX T_Wyszukaj
        ROW    498
        COL    130
        WIDTH  240
        HEIGHT 30
        FONTNAME "Arial"
        FONTSIZE 12
        TOOLTIP "Type characters to search..."
        ONCHANGE WyszukajTowar()
        ONGOTFOCUS NIL
        ONLOSTFOCUS Nil
        FONTBOLD .T.
        FONTITALIC .F.
        FONTUNDERLINE .F.
        FONTSTRIKEOUT .F.
        ONENTER OknoTabTowarow.B_Towary.SetFocus
        HELPID Nil
        TABSTOP .T.
        VISIBLE .T.
        READONLY .F.
        RIGHTALIGN .F.
        DISABLEDBACKCOLOR Nil
        DISABLEDFONTCOLOR Nil
        CASECONVERT UPPER
        BACKCOLOR NIL
        FONTCOLOR {255,0,0}
        INPUTMASK Nil
        FORMAT Nil
        VALUE ""
    END TEXTBOX
define event for keys pressed in focused BROWSE:

Code: Select all

	CREATE EVENT PROCNAME WyszukiwanieWTabeli('OknoTabTowarow', 'B_Towary','T_Wyszukaj', 'WyszukajTowar()') HWND OknoTabTowarow.B_Towary.HANDLE MSG WM_CHAR
Event handlie function:

Code: Select all

Function WyszukiwanieWTabeli 
	param cNazwaOkna, cNazwaTabeli, cNazwaPolaWyszukaj, cFunkcjaSzukajaca
	
	STATIC flag := .F.
	LOCAL hWnd, ch
	local lFound := .f.
	local cCzegoSzukac := ""

	if flag == .t.
		return nil  // avoid re-entry
	endif

	flag := .T.
	ch := HMG_GetLastCharacter(@hWnd)
	IF hWnd == GetControlHandle (cNazwaTabeli,cNazwaOkna)
		
		cCzegoSzukac := GetProperty(cNazwaOkna,cNazwaPolaWyszukaj,"Value")
		
		if (asc(ch)>31 .and. asc(ch)<128) .or. at(upper(ch),"ĄĆĘŁŃÓŚŻŹ")>0
			HMG_CleanLastCharacter(.t.)   //   avoid re-entry
			cCzegoSzukac += HMG_Upper(ch)
			hPolaWyszukaj := GetControlHandle (cNazwaPolaWyszukaj,cNazwaOkna)
			SetWindowText(hPolaWyszukaj, cCzegoSzukac)
			lFound := &cFunkcjaSzukajaca
			DoMethod(cNazwaOkna, cNazwaTabeli,"SetFocus")
		endif
	
		if asc(ch) == 8 // backspace
			hPolaWyszukaj := GetControlHandle (cNazwaPolaWyszukaj,cNazwaOkna)
			cCzegoSzukac := left(cCzegoSzukac,max(len(cCzegoSzukac)-1,0))
			SetWindowText(hPolaWyszukaj, cCzegoSzukac)
			HMG_CleanLastCharacter()   //   avoid re-entry
			DoMethod(cNazwaOkna, cNazwaTabeli,"SetFocus")
		endif
	endif
	flag := .F.
//Return if(lFound,1,NIL)
Return 1
And, proper search function, triggered by changes in Search textbox:

Code: Select all

*-------------------------
function WyszukajTowar
	local cTekstSzukany := '', cKodSzukany := ''
	local nOrder := towary->(Indexord()), i, lCyfrowy := .f., lFound := .f., sel := select()
	local nIndeksTowarow := 5
	//local nOdszukanyIndeks := 1
	// czasem przy złej kolejności kontrolek trzeba sprawdzić, czy już można działać na kontrolce
	private lAktywneSzukanieTowarow := .t.
	cOkno := ThisWindow.name
	
	if type("nOdszukanyIndeks") <> "N"
		private nOdszukanyIndeks := 1
	endif
	
	if IsControlDefined(R_IndeksTowarow, &cOkno)
		nIndeksTowarow := GetProperty(cOkno, "R_IndeksTowarow","Value")
	endif

	if  !IsControlDefined(T_Wyszukaj,&cOkno)
		return
	endif
	
	if empty(cTekstSzukany := upper(GetProperty(cOkno,"T_Wyszukaj","Value")))
		return
	endif

	select("towary")

	if nIndeksTowarow == 5
		for i:=1 to len(cTekstSzukany)
			lCyfrowy := isDigit(substr(cTekstSzukany,i,1))
			if !lCyfrowy
				exit
			endif
		next i
		if lCyfrowy
			if len(cTekstSzukany)<=len(towary->towar)
				towary->(DBSetOrder(1))
				cTekstSzukany := strzero(val(cTekstSzukany),len(towary->towar))
				nOdszukanyIndeks := 1
			endif
			lFound := towary->(DBSeek(cTekstSzukany,.t.))
			if !lFound
				// szukamy w KKresk
				cTekstSzukany := GetProperty(cOkno,"T_Wyszukaj","Value")
				towary->(DBSetOrder(4))
				lFound := towary->(DBSeek(cTekstSzukany,.t.))
				nOdszukanyIndeks := 4
			endif
			if !lFound
				cTekstSzukany := GetProperty(cOkno,"T_Wyszukaj","Value")
				// szukamy w symbolu
				towary->(DBSetOrder(3))
				lFound := towary->(DBSeek(cTekstSzukany,.t.))
				nOdszukanyIndeks := 3
			endif

		endif

		if !lFound
			cTekstSzukany := GetProperty(cOkno,"T_Wyszukaj","Value")
			towary->(DBSetOrder(2))
			lFound := towary->(DBSeek(cTekstSzukany,.t.))
			if lFound
				nOdszukanyIndeks := 2
			else
				towary->(DBSetOrder(3))
				lFound := towary->(DBSeek(cTekstSzukany,.t.))
				if lFound
					nOdszukanyIndeks := 3
				else
					//if !lSzybkaTabelaTowarow
						locate for cTekstSzukany $ nazwa
						lFound := towary->(found())
						if lFound
							nOdszukanyIndeks := -2
						//msgbox(if(lFound,"znaleziono","Nie znaleziono"))
						else
							locate for cTekstSzukany $ symbol
							lFound := towary->(found())
							if lFound
								nOdszukanyIndeks := -3
							else
								nOdszukanyIndeks := 0
							endif
						endif
					//endif
				endif
			endif
		endif
	else
		i:= GetProperty(cOkno,"R_IndeksTowarow","Value")
		towary->(DBSetOrder(i))
		nOdszukanyIndeks := i
		if i = 1
			//cTekstSzukany := StrZero(val(cTekstSzukany),len(towary->towar))
			cTekstSzukany := StrZero(val(cTekstSzukany),len(towary->towar))
		endif
		lFound := towary->(DBSeek(cTekstSzukany,.t.))
		if !lFound .and. i == 2
			locate for cTekstSzukany $ nazwa
			lFound := towary->(found())
			//MsgBox("Szukałem: "+cTekstSzukany +" w indeksie: "+str(towary->(IndexOrd()),1)+if(towary->(found())," i znalazłem", " i nie znalazłem"))
		endif
	endif
	// ten fragment trzeba poprawić
	// żeby sprawdzał czy początek pola z bazy jest równy temu, co szukam
	do case
		case nOdszukanyIndeks  == 1
			//lFound := towary->towar = cTekstSzukany
		case nOdszukanyIndeks  == 2
			// rezygnuję, bo mogłem szukać po fragmencie nazwy
			//lFound := cTekstSzukany == left(towary->nazwa,len(cTekstSzukany))
		case nOdszukanyIndeks  == 3
			lFound := cTekstSzukany == left(towary->symbol,len(cTekstSzukany))
		case i == 4
			lFound := cTekstSzukany == left(towary->kodkresk,len(cTekstSzukany))
	endcase

	towary->(DBSetOrder(nOrder))

	if lFound
		SetProperty(cOkno,"B_Towary","Value", towary->(Recno()))
		
	else
		PlayBeep()
		nPos := (len(GetProperty(cOkno,"T_Wyszukaj","Value"))-1)
		SetProperty(cOkno,"T_Wyszukaj","Value", left(GetProperty(cOkno,"T_Wyszukaj","Value"), nPos))
		SetProperty(cOkno,"T_Wyszukaj","CaretPos",nPos)
	endif

 return

User avatar
Clip2Mania
Posts: 95
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium
Been thanked: 1 time

Post by Clip2Mania » Thu Jun 26, 2014 10:04 am

Thanks Marek! I'll try this.
Still learning event handlers... :)

User avatar
esgici
Posts: 4337
Joined: Wed Jul 30, 2008 9:17 pm
DBs Used: DBF
Location: iskenderun / Turkiye
Has thanked: 221 times
Been thanked: 77 times
Contact:

Post by esgici » Thu Jun 26, 2014 11:53 am

Clip2Mania wrote:I would like to implement an incremental search in a BROWSE.
E.g. When typing a character, 'seek' to the first occurrence in the indexed table - when typing a second character, seeking further in the index, and so on. "Clearing" the seek-string by means of a Ctrl-Key combination.
A bit like the example GridIncrementalSearch in \SAMPLES\Controls\Grid.
Is this possible in a BROWSE ? How can I do that?

Best Regards,
Hi

Have you ever seen this ( QuickSearch.zip ) ?

( Older and simpler ;) )

Regards

--
Viva INTERNATIONAL HMG :D

User avatar
Clip2Mania
Posts: 95
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium
Been thanked: 1 time

Post by Clip2Mania » Thu Jun 26, 2014 2:25 pm

That is a VERY nice and simple one indeed! ;)

I derived my own "simple one" from Marek's code
CREATE EVENT PROCNAME QuickSearch() HWND MainForm.br_Main.HANDLE MSG WM_CHAR
Then did a simple seek

Code: Select all

function QuickSearch()
local ch, hWnd

ch := HMG_GetLastCharacter(@hWnd)
if asc(ch) = 8
  cStr:=if(len(cStr)>1,left(cStr,len(cStr)-1),"")
else
	cStr:=cStr+upper(ch)
endif

if !DBSEEK(cStr,.T.)
  DBSKIP(-1)
endif

HMG_CleanLastCharacter()   
MainForm.Statusbar.Item(1):=cStr
MainForm.br_Main.Value:=recno()
MainForm.br_Main.Setfocus
return 1
Thanks also for your contribution esgici!

User avatar
Clip2Mania
Posts: 95
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium
Been thanked: 1 time

Post by Clip2Mania » Fri Jun 27, 2014 8:19 am

Can anybody help me what I have to change in the above code to also be able to trap the TAB and Function keys?
Thanks

(Please discard - found solution to the above changing WM_CHAR to WM_KEYDOWN)
Last edited by Clip2Mania on Fri Jun 27, 2014 10:15 am, edited 1 time in total.

User avatar
Rathinagiri
Posts: 5163
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Has thanked: 129 times
Been thanked: 130 times
Contact:

Post by Rathinagiri » Fri Jun 27, 2014 10:14 am

You can check using

if HMG_VirtualKeyIsPressed ( VK_F1 )
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.

User avatar
Clip2Mania
Posts: 95
Joined: Fri Jun 13, 2014 7:16 am
Location: Belgium
Been thanked: 1 time

Post by Clip2Mania » Fri Jun 27, 2014 10:30 am

Hi Rathinagiri,

I get a "Referenced, missing, but unknown function(s): MSG()" when I do that..
Something include I need to add?

User avatar
Rathinagiri
Posts: 5163
Joined: Tue Jul 29, 2008 6:30 pm
DBs Used: MariaDB, SQLite, SQLCipher and MySQL
Location: Sivakasi, India
Has thanked: 129 times
Been thanked: 130 times
Contact:

Post by Rathinagiri » Fri Jun 27, 2014 2:39 pm

Your HMG version?
East or West HMG is the Best.
South or North HMG is worth.
...the possibilities are endless.

Post Reply