Usar valor del Get en COMBOBOX para luego rellenar array

Post Reply
User avatar
joseluisysturiz
Posts: 2069
Joined: Fri Jan 06, 2006 9:28 pm
Location: Guatire - Caracas - Venezuela
Contact:

Usar valor del Get en COMBOBOX para luego rellenar array

Post by joseluisysturiz »

Saludos, mi necesidad es la siguiente, tengo un COMBOBOX vacio o dbconbo con GET, necesito que al entrar un valor en el GET y dar enter, vaya a una función, alli voy buscar un una tabla con un query where y LIKE los registros coincidentes con el valor entrado en el GET y lluego con los registros que hayan, crear un array y cambiar el array vacío o el que tenga. Por el.nuevo array, y esos sean los valores a desplegar para seleccionar en el combo box.. el valor lo estoy viendo solo si le doy al botón del COMBOBOX para desplegar y necesito sea con el enter en el GET como un valid pero del GET y no del combobox .no se si eso es posible... y recuerden debo reemplazar el array del combobox por un nuevo array y liuego esos sean los valores a mostrar para seleccionar del combobox.. gracias

Dios no está muerto...

Gracias a mi Dios ante todo!
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by Antonio Linares »

Estimado Jose Luis,

Prueba así:

Code: Select all | Expand

#include "FiveWin.ch"

function Main()
   local oDlg, cBuscar := Space( 40 ), oCbx, aVacio := {}

   USE clientes NEW SHARED   // tu tabla

   DEFINE DIALOG oDlg TITLE "Búsqueda" SIZE 320, 200

   @ 1, 2 SAY "Buscar:" OF oDlg

   @ 3, 2 COMBOBOX oCbx VAR cBuscar ITEMS aVacio ;
      SIZE 200, 120 ;
      STYLE CBS_DROPDOWN ;          // <-- editable (con GET)
      VALID BuscarYRecargar( oCbx, cBuscar )   // se dispara al dar ENTER

   @ 3, 26 BTNBMP ... OF oDlg  // otros controles

   ACTIVATE DIALOG oDlg CENTER
return nil

function BuscarYRecargar( oCbx, cTexto )
   local aItems := {}

   cTexto := AllTrim( cTexto )

   // ===== Aquí tu QUERY WHERE ... LIKE =====
   // SQL (FWMaria/ADO/SQLite): SELECT nombre FROM clientes
   //                           WHERE UPPER(nombre) LIKE '%" + Upper(cTexto) + "%'
   //
   // Equivalente con DBF (recorriendo y filtrando con AT):
   IF ! Empty( cTexto )
      clientes->( dbGoTop() )
      WHILE ! clientes->( Eof() )
         IF AT( Upper( cTexto ), Upper( clientes->nombre ) ) > 0
            AAdd( aItems, clientes->nombre )
         ENDIF
         clientes->( dbSkip() )
      END
   ENDIF
   // =========================================

   // Reemplaza el array vacío / anterior por el nuevo:
   oCbx:SetItems( aItems, .T. )

   // (Opcional) Despliega la lista de inmediato para elegir:
   // oCbx:Open()

return .T.   // .T. para que el foco pueda salir del control

Si quieres que al dar Enter la lista se abra sola y el foco se quede en el GET (sin saltar al siguiente control), intercepta el Enter en el oGet y evitas la navegación por defecto:
// después de crear oCbx:

Code: Select all | Expand

local bDef := oCbx:oGet:bKeyChar
oCbx:oGet:bKeyChar := { | nKey | ;
   If( nKey == 13,                                ; // VK_RETURN
      ( BuscarYRecargar( oCbx, cBuscar ),         ; // tu búsqueda
        oCbx:Set( cBuscar ),                      ; // deja el texto tecleado
        oCbx:Open(),                              ; // abre el desplegable
        0 ),                                      ; // 0 = no navegar
      Eval( bDef, nKey ) ) }                      // resto de teclas normal

Y en BuscarYRecargar haz oCbx:SetItems( aItems, .T. ) y ya no necesitas el VALID (o puedes dejarlo también; no molesta).

Si usas TDbCombo (dbcombo con GET)
El método equivalente es SetItems( aItems, aList, .T. ) (III params). Lo mismo: búscalo en VALID y reemplaza el array.
¿Quieres que te adapte el ejemplo a tu motor concreto (FWMaria/ADO/SQLite o DBF) o a TDbCombo?

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
joseluisysturiz
Posts: 2069
Joined: Fri Jan 06, 2006 9:28 pm
Location: Guatire - Caracas - Venezuela
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by joseluisysturiz »

Saludos mr Antonio. Voy a probar lo que envías y luego comento.. gracias

Dios no está muerto...

Gracias a mi Dios ante todo!
User avatar
joseluisysturiz
Posts: 2069
Joined: Fri Jan 06, 2006 9:28 pm
Location: Guatire - Caracas - Venezuela
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by joseluisysturiz »

Antonio Linares wrote: Sun Jul 12, 2026 9:17 am

Estimado Jose Luis,

Prueba así:

Code: Select all | Expand

#include "FiveWin.ch"

function Main()
   local oDlg, cBuscar := Space( 40 ), oCbx, aVacio := {}

   USE clientes NEW SHARED   // tu tabla

   DEFINE DIALOG oDlg TITLE "Búsqueda" SIZE 320, 200

   @ 1, 2 SAY "Buscar:" OF oDlg

   @ 3, 2 COMBOBOX oCbx VAR cBuscar ITEMS aVacio ;
      SIZE 200, 120 ;
      STYLE CBS_DROPDOWN ;          // <-- editable (con GET)
      VALID BuscarYRecargar( oCbx, cBuscar )   // se dispara al dar ENTER

   @ 3, 26 BTNBMP ... OF oDlg  // otros controles

   ACTIVATE DIALOG oDlg CENTER
return nil

function BuscarYRecargar( oCbx, cTexto )
   local aItems := {}

   cTexto := AllTrim( cTexto )

   // ===== Aquí tu QUERY WHERE ... LIKE =====
   // SQL (FWMaria/ADO/SQLite): SELECT nombre FROM clientes
   //                           WHERE UPPER(nombre) LIKE '%" + Upper(cTexto) + "%'
   //
   // Equivalente con DBF (recorriendo y filtrando con AT):
   IF ! Empty( cTexto )
      clientes->( dbGoTop() )
      WHILE ! clientes->( Eof() )
         IF AT( Upper( cTexto ), Upper( clientes->nombre ) ) > 0
            AAdd( aItems, clientes->nombre )
         ENDIF
         clientes->( dbSkip() )
      END
   ENDIF
   // =========================================

   // Reemplaza el array vacío / anterior por el nuevo:
   oCbx:SetItems( aItems, .T. )

   // (Opcional) Despliega la lista de inmediato para elegir:
   // oCbx:Open()

return .T.   // .T. para que el foco pueda salir del control

Si quieres que al dar Enter la lista se abra sola y el foco se quede en el GET (sin saltar al siguiente control), intercepta el Enter en el oGet y evitas la navegación por defecto:
// después de crear oCbx:

Code: Select all | Expand

local bDef := oCbx:oGet:bKeyChar
oCbx:oGet:bKeyChar := { | nKey | ;
   If( nKey == 13,                                ; // VK_RETURN
      ( BuscarYRecargar( oCbx, cBuscar ),         ; // tu búsqueda
        oCbx:Set( cBuscar ),                      ; // deja el texto tecleado
        oCbx:Open(),                              ; // abre el desplegable
        0 ),                                      ; // 0 = no navegar
      Eval( bDef, nKey ) ) }                      // resto de teclas normal

Y en BuscarYRecargar haz oCbx:SetItems( aItems, .T. ) y ya no necesitas el VALID (o puedes dejarlo también; no molesta).

Si usas TDbCombo (dbcombo con GET)
El método equivalente es SetItems( aItems, aList, .T. ) (III params). Lo mismo: búscalo en VALID y reemplaza el array.
¿Quieres que te adapte el ejemplo a tu motor concreto (FWMaria/ADO/SQLite o DBF) o a TDbCombo?

***********************

Antonio, uso es DBCOMMBO, fijate, el VALID se dispara al dar el ENTER, pero no lleva a la funcion, el valor entrado en el GET, pero si le doy al boton de despliegue del DBCOMBO, entonces se dispara el VALID y si lleva el valor entrado en el GET, necesito es que lo lleve al dar enter...estoy usando mysql.. gracias

REDEFINE DBCOMBO aGetLla[10] VAR aVarLla[10] ID 4004 OF oFldx:aDialogs[1] UPDATE ; // NOM.SEC.ORI
ITEMS aSecOri1 ;
LIST aSecOri2 ;
VALID ( nuevo_buscador( aVarLla[10], aGetLla[10] ) )

---------------

FUNCTION nuevo_buscador( cSecOriDes, oGetOriDes ) // NUEVO BUSCADOR DESDE DBCOMBO - 26/06/2026

? "nuevo_buscador: ", cSecOriDes

RETURN .t.

Dios no está muerto...

Gracias a mi Dios ante todo!
User avatar
Antonio Linares
Site Admin
Posts: 44515
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by Antonio Linares »

Estimado Jose Luis,

El síntoma que describes tiene una causa concreta en la clase TDBCombo: el VALID se evalúa a través del LostFocus, y en TDBCombo la variable enlazada (bSetGet) se actualiza después de llamar al LostFocus del padre (que es donde se dispara el VALID).

Mira el método LostFocus de TDBCombo:

source/classes/dbcombo.prg

Code: Select all | Expand

[code]METHOD LostFocus( hWndGetFocus ) CLASS TDBCombo
   local nAt := ::SendMsg( CB_GETCURSEL )
   ...
   uRet := ::Super:LostFocus( hWndGetFocus )   // <-- aquí se evalúa el VALID
   if !::lIndexVar
      Eval( ::bSetGet, uVal )                  // <-- la variable se actualiza DESPUÉS
   endif
return uRet[/code]
``` [0-cite-0](#0-cite-0) 

Cuando das ENTER, la navegación provoca el `LostFocus`, y el `VALID` corre **antes** de que `Eval( ::bSetGet, uVal )` haya volcado el texto tecleado a `aVarLla[10]`. Por eso tu primer parámetro `cSecOriDes` llega vacío/con el valor anterior. [0-cite-1](#0-cite-1) 

En cambio, cuando pulsas el botón de despliegue y seleccionas, se dispara `Change()`, que sí hace `Eval( ::bSetGet, ... )` y `::oGet:VarPut( Eval( ::bSetGet ) )` **antes** de perder el foco, por eso ahí sí llega el valor correcto. [0-cite-2](#0-cite-2) 

## Solución

No dependas de la variable enlazada dentro del `VALID`; lee el texto directamente del control. En tu `VALID` ya estás pasando el objeto del combo (`aGetLla[10]`), así que usa su método `GetText()` (que devuelve el texto real del edit del combo, como se ve en `ListGet`): [0-cite-3](#0-cite-3) 

```harbour
[code]REDEFINE DBCOMBO aGetLla[10] VAR aVarLla[10] ID 4004 OF oFldx:aDialogs[1] UPDATE ;
   ITEMS aSecOri1 ;
   LIST  aSecOri2 ;
   VALID ( nuevo_buscador( aGetLla[10] ) )

FUNCTION nuevo_buscador( oGetOriDes )
   LOCAL cTexto := AllTrim( oGetOriDes:GetText() )   // texto tecleado real
   ? "nuevo_buscador: ", cTexto
   // ... aquí tu SELECT ... WHERE ... LIKE '%' + cTexto + '%' (MySQL)
RETURN .t.[/code]

Así, tanto en ENTER como al desplegar, GetText() te devuelve lo que hay escrito en el GET del combo, sin depender del orden en que se actualiza aVarLla[10].

Si prefieres seguir usando la variable, otra opción es forzar el volcado antes de buscar dentro de la función: oGetOriDes:oGet:GetText() sobre el oGet interno del control da el mismo resultado.

regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
joseluisysturiz
Posts: 2069
Joined: Fri Jan 06, 2006 9:28 pm
Location: Guatire - Caracas - Venezuela
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by joseluisysturiz »

Saludos, Antonio reviso. Pruebo ...y luego comento.. gracias

Dios no está muerto...

Gracias a mi Dios ante todo!
User avatar
joseluisysturiz
Posts: 2069
Joined: Fri Jan 06, 2006 9:28 pm
Location: Guatire - Caracas - Venezuela
Contact:

Re: Usar valor del Get en COMBOBOX para luego rellenar array

Post by joseluisysturiz »

Antonio Linares wrote: Fri Jul 17, 2026 8:44 am

Estimado Jose Luis,

El síntoma que describes tiene una causa concreta en la clase TDBCombo: el VALID se evalúa a través del LostFocus, y en TDBCombo la variable enlazada (bSetGet) se actualiza después de llamar al LostFocus del padre (que es donde se dispara el VALID).

Mira el método LostFocus de TDBCombo:

source/classes/dbcombo.prg

Code: Select all | Expand

[code]METHOD LostFocus( hWndGetFocus ) CLASS TDBCombo
   local nAt := ::SendMsg( CB_GETCURSEL )
   ...
   uRet := ::Super:LostFocus( hWndGetFocus )   // <-- aquí se evalúa el VALID
   if !::lIndexVar
      Eval( ::bSetGet, uVal )                  // <-- la variable se actualiza DESPUÉS
   endif
return uRet[/code]
``` [0-cite-0](#0-cite-0) 

Cuando das ENTER, la navegación provoca el `LostFocus`, y el `VALID` corre **antes** de que `Eval( ::bSetGet, uVal )` haya volcado el texto tecleado a `aVarLla[10]`. Por eso tu primer parámetro `cSecOriDes` llega vacío/con el valor anterior. [0-cite-1](#0-cite-1) 

En cambio, cuando pulsas el botón de despliegue y seleccionas, se dispara `Change()`, que sí hace `Eval( ::bSetGet, ... )` y `::oGet:VarPut( Eval( ::bSetGet ) )` **antes** de perder el foco, por eso ahí sí llega el valor correcto. [0-cite-2](#0-cite-2) 

## Solución

No dependas de la variable enlazada dentro del `VALID`; lee el texto directamente del control. En tu `VALID` ya estás pasando el objeto del combo (`aGetLla[10]`), así que usa su método `GetText()` (que devuelve el texto real del edit del combo, como se ve en `ListGet`): [0-cite-3](#0-cite-3) 

```harbour
[code]REDEFINE DBCOMBO aGetLla[10] VAR aVarLla[10] ID 4004 OF oFldx:aDialogs[1] UPDATE ;
   ITEMS aSecOri1 ;
   LIST  aSecOri2 ;
   VALID ( nuevo_buscador( aGetLla[10] ) )

FUNCTION nuevo_buscador( oGetOriDes )
   LOCAL cTexto := AllTrim( oGetOriDes:GetText() )   // texto tecleado real
   ? "nuevo_buscador: ", cTexto
   // ... aquí tu SELECT ... WHERE ... LIKE '%' + cTexto + '%' (MySQL)
RETURN .t.[/code]

Así, tanto en ENTER como al desplegar, GetText() te devuelve lo que hay escrito en el GET del combo, sin depender del orden en que se actualiza aVarLla[10].

Si prefieres seguir usando la variable, otra opción es forzar el volcado antes de buscar dentro de la función: oGetOriDes:oGet:GetText() sobre el oGet interno del control da el mismo resultado.

Saludos Antonio, lamentablemente o no supe como hacerlo o no funciono lo que me sugeriste, ya que aunque haga AllTrim( oGetOriDes:GetText(), en la funcion donde envio el oGet que es buscador(), solo muestra el valor del GET cuando se dispara el VALID que es cuando le doy al boton de despliegue... voy seguir haciendo prueba, lo que no quiero es hacer otro GET ya que el mismo DBCOMBO trae y asi evito dos objetos, si no hay manera, tendre que hacerlo, pero espero alguna otra sugerencia a ver..gracias

Dios no está muerto...

Gracias a mi Dios ante todo!
Post Reply