Ricerca approssimata nel combobox

Moderator: Enrico Maria Giordano

Post Reply
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Ricerca approssimata nel combobox

Post by Ugo »

Intanto buon anno a tutti,
tempo fa ho inserito la ricerca approssimata nel combo box, intendo che quando questo ha il focus, digitando sulla tastiera si sposta l'item al primo che corrisponde a quanto fino a quel momento è stato digitato.
La modifica fatta al Combobox è:

Code: Select all

//----------------------------------------------------------------------------//
#ifdef UGO

METHOD GotFocus() CLASS TComboBox
   ::cSearchKey := ""
   Return Super:GotFocus()
#endif
//----------------------------------------------------------------------------//

METHOD KeyChar( nKey, nFlags ) CLASS TComboBox

#ifdef UGO
   local nNewAT := 0, nOldAT := ::nAT

   // Incremental search
   if nKey = VK_DELETE  // 32   // space resets the search
      ::cSearchKey := ""
      ::Set(1)
   else
      if nKey = VK_BACK
         ::cSearchKey := left( ::cSearchKey, Len(::cSearchKey) - 1 )
      else
         ::cSearchKey += upper( chr( nKey ))
      endif
      nNewAT := ascan( ::aItems, {|x| upper(x) = ::cSearchKey} )
      ::Select( IIF( nNewAt > 0, nNewAt, ::nAT ))
   endif

   if ::bChange != nil .and. ( nNewAT != nOldAt .and. nNewAt != 0 )
      Eval( ::bChange, Self, ::varGet() )
   endif

   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif

   Super:KeyChar(nKey, nFlags)

   RETURN 0   // Must be 0 - We don't want API default behavior.
#else
   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif

   return Super:KeyChar( nKey, nFlags )
#endif
Non funziona se l'utente digita il "." (e non so con quale altro carattere)
in pratica nella variabile che dovrebbe contenere l'item c'è un numero che manda in errore la procedura al primo utilizzo.

Qualcuno ha un suggerimento?

Grazie per l'aiuto.
Ciao, best regards,
Ugo
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Re: Ricerca approssimata nel combobox

Post by Ugo »

Ugo wrote: Non funziona se l'utente digita il "." (e non so con quale altro carattere)
in pratica nella variabile che dovrebbe contenere l'item c'è un numero che manda in errore la procedura al primo utilizzo.
Integrazione:
- Togliendo la mia modifica non vi è errore
- Il numero che appare è la posizione dell'Item nell'elenco
Ciao, best regards,
Ugo
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Per verificare l'anomalia:
Inserire nel file Combobox.prg:

Code: Select all

DATA ::cSearchKey

METHOD GotFocus( )
Nel metodo New e Redefine aggiungere:

Code: Select all

   ::cSearchKey := ""
tra le definizioni delle variabili, inserire anche il codice del primo post.

infine lo si può poi testare con:

Code: Select all

function Main()

   local oDlg, oSay
   local oCbx3
   local cItem3 := "One", cItem4 := "None"

   SET _3DLOOK ON

   DEFINE DIALOG oDlg

   @ 1,1 COMBOBOX oCbx3 VAR cItem3 ITEMS { "One", "Two", "Three" } ;
      OF oDlg ;
      ON CHANGE ( cItem4 := cItem3, oSay:Refresh() ) ;
      VALID ( cItem4 := cItem3, oSay:Refresh(), .t. )

   @ 3,1 SAY oSay PROMPT cItem4 OF oDlg COLOR "R+/W"

   ACTIVATE DIALOG oDlg CENTERED

return nil
usando la tastiera mi sposto in alto/basso e la say scrive i valori dell'array
premendo invece "t" e "h" seleziono correttamente Three mentre
se premo il punto da quel momento se vado su o giù o seleziono una voce con il mouse, la say visualizza la posizione numerica della scelta, la tastiera a parte i cursori non funziona più.

Grazie per i suggerimenti.
Ciao, best regards,
Ugo
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Ugo,

Place a MsgInfo( nNewAt ) after

nNewAT := ascan( ::aItems, {|x| upper(x) = ::cSearchKey} )

and check what value you get when you press a "."
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Antonio Linares wrote:Place a MsgInfo( nNewAt ) after
nNewAT := ascan( ::aItems, {|x| upper(x) = ::cSearchKey} )
and check what value you get when you press a "."
Dear Antonio,
I press "." and do not go in this point but the combobox set the first value and set the variable to numeric for return the position of array for the actual selection.
Ciao, best regards,
Ugo
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Qualcuno ha provato?

Dopo vari test ho trovato questo work-around che però non mi soddisfa per l'applicazione finale, per la quantità notevole di modifiche.

Work-around:

Code: Select all

   @ 1,1 COMBOBOX oCbx3 VAR cItem3 ITEMS { "One", "Two", "Three" } ;
      OF oDlg ;
      ON CHANGE ( IF( ValType( cItem3 ) == "N", ;
                                cItem3 := oCbx3:aItems[cItem3],), ;
                            cItem4 := cItem3,;
                            oSay:Refresh() ) ;
      VALID ( IF( ValType( cItem3 ) == "N", ;
                           cItem3 := oCbx3:aItems[cItem3],), ;
                   cItem4 := cItem3,;
                   oSay:Refresh(), .t. )
Non capisco come mai non viene invocato il metodo KeyChar dal tasto '.'
e di conseguenza come intercettarlo per evitare il cambio di variabile.
Ciao, best regards,
Ugo
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Antonio Linares wrote:...
and check what value you get when you press a "."
Antonio,
in KeyDown Method, the value of nKey when i press a "." is 190,
but in the KeyChar Method is impossible (for me) find the value.
Ciao, best regards,
Ugo
User avatar
Ugo
Posts: 283
Joined: Sat Oct 15, 2005 6:40 am
Location: Turin, Italy

Post by Ugo »

Finalmente ho risolto, di seguito ci sono le modifiche da inserire nel Combobox.prg per ottenere la ricerca incrementale nel combobox classico, non ho fatto prove (per ora) con gli altri tipi:

Code: Select all

#define UGO
//----------------------------------------------------------------------------//
CLASS TComboBox FROM TControl
   ...
   #ifdef UGO
       DATA   cSearchKey   // Holds current search key for incremental search.
   #endif
   ...
   #ifdef UGO
       METHOD GotFocus( )
   #endif
ENDCLASS
... 
//----------------------------------------------------------------------------//
METHOD New( ... ) CLASS TComboBox
...
   ::oFont     = oFont
#ifdef UGO
   ::cSearchKey := ""
#endif
...
//----------------------------------------------------------------------------//
METHOD ReDefine( ... ) CLASS TComboBox
...
   ::nStyle    = nStyle
#ifdef UGO
   ::cSearchKey := ""
#endif
...
//----------------------------------------------------------------------------//
#ifdef UGO
METHOD GotFocus() CLASS TComboBox
   ::cSearchKey := ""
   Return Super:GotFocus()
#endif
//----------------------------------------------------------------------------//
METHOD KeyChar( nKey, nFlags ) CLASS TComboBox
#ifdef UGO
   local nNewAT := 0, nOldAT := ::nAT, uItem
   // Incremental search
   Do Case
   Case nKey = 32   // VK_DELETE (DO NOT WORK!)
      ::cSearchKey := ""
      nNewAt := 1
      uItem := ::aItems[nNewAt]
   Case nKey = VK_BACK
      ::cSearchKey := Left( ::cSearchKey, Len(::cSearchKey) - 1 )
   Case nKey = 190
      nKey := 0
      ::cSearchKey += "."
   OtherWise
      ::cSearchKey += Upper( Chr( nKey ))
   endcase
   If Empty( uItem )
      IF nNewAt == 0
         nNewAt := AScan( ::aItems, {|x| Upper(x) = ::cSearchKey } )
         uItem := ::aItems[ IIF( nNewAt > 0, nNewAt, ::nAT ) ]
      ELSE
         uItem := ::aItems[Max( nNewAt, 1)]
      ENDIF
   ENDIF
   ::Set( uItem )
   if ::bChange != nil .and. ( nNewAT != nOldAt .and. nNewAt != 0 )
      Eval( ::bChange, Self, ::varGet() )
   endif
   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif
   // Return Super:KeyChar( nKey, nFlags )
   RETURN 0   // Must be 0 - We don't want API default behavior.
#else
   // Standard keychar method
   if nKey == VK_RETURN
      return ::oWnd:GoNextCtrl( ::hWnd )
   endif
   return nRet
#endif
Il tutto è messo sotto define per passare al volo alla versione standard e per gestire le nuove versioni di Antonio ;-)

Spero possa essere utile.
Ciao, best regards,
Ugo
Post Reply