FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour Consulta para Antonio
Posts: 27
Joined: Tue Aug 12, 2025 12:29 PM

Consulta para Antonio

Posted: Sat Aug 08, 2026 10:21 AM

Hola Antonio, estoy usando en un ABM sql y xbrowse, como puedo hacer para que xbrowse tome una función de busqueda mia en lugar de la propia.

Lo que pretendo hacer es que busque más de una palabra en cualquier lugar que se encuentre cada una.

SELECT * FROM dbo.Stock AS s where s.Descri like '%APLI%' and s.Descri like '%350%' and s.Descri like '%ZIO%' order by s.Descri

mi función arma la busqueda así.

Esto lo uso con listbox y quiero pasarlo a xbrowse porque me gusta más xbrowse.

Saludos Jorge

Saludos

Jorge
Posts: 44508
Joined: Thu Oct 06, 2005 05:47 PM

Re: Consulta para Antonio

Posted: Sat Aug 08, 2026 04:42 PM

Estimado Jorge,

Es más fácil de lo que parece: la búsqueda incremental de TXBrowse se ejecuta a través del codeblock bSeek, que es un DATA
público y reemplazable (está declarado en source/classes/xbrowse.prg:169 con el comentario "block expression for autoincremental
search"). Cada datasource solo le pone un default (SetAdo asigna {|c| ::AdoIncrSeek(c)} en la línea 7044), así que basta con
asignar el tuyo después de cargar los datos.

Tenés dos caminos, según cómo estés trayendo los datos:

Opción 1 (recomendada si usás ADO): lIncrFilter + bFilterExp

En modo lIncrFilter := .t., AdoIncrSeek (xbrowse.prg:8213) evalúa bFilterExp con el texto tipeado y aplica lo que devuelvas como
oRs:Filter. O sea, no reconsultás al servidor: ADO filtra el recordset local, y tu bloque arma la condición multi-palabra.

     oBrw:lIncrFilter := .t.
     oBrw:bFilterExp  := { | cSeek | FiltroStock( cSeek ) }
     function FiltroStock( cSeek )
        local cExpr := ""
        local cWord
        for each cWord in hb_ATokens( AllTrim( cSeek ), " " )
           if ! Empty( cWord )
              cExpr += If( Empty( cExpr ), "", " AND " ) + ;
                       "Descri LIKE '*" + StrTran( cWord, "'", "''" ) + "*'"
           endif
        next
        // Ojo: con cSeek vacío hay que devolver algo siempre-verdadero,
        // porque AdoIncrSeek solo toca oRs:Filter si cExpr no está vacío
     return If( Empty( cExpr ), "1=1", cExpr )

Detalle importante: la propiedad Filter de ADO usa * (también acepta %) como comodín, no la sintaxis de SQL Server. El resultado
equivale a tu LIKE '%APLI%' AND LIKE '%350%' AND LIKE '%ZIO%'.

Opción 2 (cualquier datasource): reemplazar bSeek y reconsultar

Si preferís ir al servidor con tu SELECT exacto, asigná bSeek con tu función, que recibe el string tipeado y debe devolver .T.
si encontró algo (el método Seek() en xbrowse.prg:9798 evalúa ese bloque y hace el Refresh solo si devolvés verdadero):

     oBrw:bSeek := { | cSeek | BuscarStock( oBrw, oCn, cSeek ) }
     function BuscarStock( oBrw, oCn, cSeek )
        local cWhere := ""
        local cWord, oRs
        for each cWord in hb_ATokens( AllTrim( cSeek ), " " )
           if ! Empty( cWord )
              cWhere += If( Empty( cWhere ), "", " AND " ) + ;
                        "s.Descri LIKE '%" + StrTran( cWord, "'", "''" ) + "%'"
           endif
        next
        oRs := oCn:Execute( "SELECT * FROM dbo.Stock AS s " + ;
           If( Empty( cWhere ), "", "WHERE " + cWhere ) + " ORDER BY s.Descri" )
        if oRs:RecordCount > 0
           oBrw:SetAdo( oRs )   // re-carga el browse con el nuevo recordset
           return .t.
        endif
     return .f.

La opción 2 tiene sentido si la tabla es grande y no querés bajar todo el stock al recordset; para un ABM típico, la opción 1
filtrando local es más fluida (una sola consulta al abrir).

Un par de notas:
• Asigná bSeek/bFilterExp después del SetAdo() (o del NewFrom... que uses), porque esos métodos pisan el default.
• Si tu fuente no es ADO (por ejemplo Dolphin/MySQL), bFilterExp no aplica — ahí usá la opción 2, o fijate que lSeekWild := .t.
ya te da LIKE '%texto%' pero solo con una palabra.

¿Con qué datasource estás trabajando en ese ABM (ADO recordset, conexión directa SQL Server, otra)? Si me pasás el fragmento
donde creás el xBrowse te lo dejo ajustado.

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 27
Joined: Tue Aug 12, 2025 12:29 PM

Re: Consulta para Antonio

Posted: Mon Aug 10, 2026 12:08 PM

Excelente, lo voy a probar y te cuento.

Muchas gracias Jorge

Saludos

Jorge
Posts: 27
Joined: Tue Aug 12, 2025 12:29 PM

Re: Consulta para Antonio resuelto

Posted: Mon Aug 31, 2026 01:02 PM

Hola Antonio, después de algunas pruebas quedó así y funciona perfecto:

oBrw:bSeek := { | cSeek | BuscarStock( oBrw, oCon, cSeek ) }

function BuscarStock( oBrw, oCn, cSeek )
local cWhere := ""
local cWord, oRs

  if oBrw:oSortCol != NIL
     xordenadopor := oBrw:oSortCol:cExpr
     xcampobusca  := oBrw:oSortCol:cExpr
     else
     if empty( xOrdenadoPor )
        xOrdenadoPor = xcampobusca
     endif
  endif

      // oBrw:SelectedCol:csortorder

    for each cWord in hb_ATokens( AllTrim( cSeek ), " " )
       if ! Empty( cWord )
          cWhere += If( Empty( cWhere ), "", " AND " ) + ;
                    xcampobusca  + " LIKE '%" + StrTran( cWord, "'", "''" ) + "%'"
       endif
    next

    wsql := cSQL + ; //  "SELECT * FROM dbo.Stock AS s " + ;
    If( Empty( cWhere ), "", "WHERE " + cWhere ) + " ORDER BY " + xOrdenadopor

    woRS1 := CargaRecordSet( WSQL, CadenaCon )

    if wors1 <> nil .and. woRs1:RecordCount > 0
       cdbf := wors1
       oBrw:SetAdo( cdbf )   // re-carga el browse con el nuevo recordset
       obrw:update()
       obrw:refresh()
       obrw:setfocus()
       return .t.
    endif
 return .f.

Muchas gracias
Saludos
Jorge

Saludos

Jorge

Continue the discussion