Page 1 of 2

XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 7:12 pm
by TimStone
With a DBF, using xBrowse, I can implement an incremental search as follows:

oLbx:bSeek := { |c| oDbf:Seek( c ) }

I am having difficulty with an incremental search on an array in an xBrowse.

Can someone point me in the right direction ? For an example, use the browse object oLbx and the array list is aValList

Thanks

Re: XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 8:20 pm
by Antonio Linares
Tim,

Please try this:

oBrowse:bSeek := { | c | SeekOnArray( oBrowse, oBrowse:aArrayData, c ) }

Re: XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 8:57 pm
by TimStone
OK ... this is a 3 element array so I want to do the seek on element 3. It is in the first column.

As your code is written it does not move the array ...

How can I limit to column 1, element 3 for the seek ?

Re: XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 9:23 pm
by Antonio Linares
Tim,

function SeekOnArray() source code is located in source\classes\xbrowse.prg. You can easily trace it and check how it is behaving, or please provide a small working example that we may test here, thanks

Re: XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 10:18 pm
by TimStone
I guess I'm trying to understand the logic of SeekOnArray.

It scans the array of columns for one that is not empty with a cOrder value. How do I set the cOrder value for a multi dimensional array ? I do not see anything in the existing code that does this.

That is probably why I can't get this to work.

Tim

Re: XBrowse Array Incremental Search

PostPosted: Tue Feb 09, 2010 11:43 pm
by Antonio Linares
Tim,

You can use that DATA cOrder value to select the column where you want to do the search :-)

oBrowse:aCols[ 1 ]:cOrder = "A" // "A" for Ascending, "D" for Descending

1 for first column, etc.

Re: XBrowse Array Incremental Search

PostPosted: Wed Feb 10, 2010 2:04 am
by TimStone
Here is the actual function. The array passed to it is a 3 element array of GL numbers. It displays with the number in column 1. The idea is to be able to type in a GL number and reposition the browse. Now it just dings when I type in a number. Except for the incremental seek not functioning, it works perfectly.

FUNCTION GLFind2( )

// Declare EXTERNAL variables
MEMVAR oWnd, aGLList
// Declare LOCAL variables
PRIVATE lx, ItmFound := .F., cGLRetVal, oDlgl, oLbxgl, nPos, oHd1, oHd2, nItem := 1

// Create the dialog
DEFINE BRUSH olBrush RESOURCE "SKY"
DEFINE DIALOG oDlglf RESOURCE "PROBROW" BRUSH olBrush transparent OF oWnd TITLE "GL Accounts" FONT oWnd:oFont

// Create the control buttons
REDEFINE BTNBMP RESOURCE "HROK" PROMPT "Accept" ID 2101 of oDlglf TOOLTIP "Accept" NOBORDER TRANSPARENT ;
ACTION ( cGLRetVal := aGLList[oLbxglf:nArrayAt][3], oDlglf:End()) MESSAGE "Use the highlighted GL Account"

// Create the browse
REDEFINE XBROWSE oLbxglf ID 2100 OF oDlglf ON DBLCLICK( cGLRetVal := aGLList[oLbxglf:nArrayAt][3], oDlglf:End()) ;
MESSAGE "Double click on an item to select an account"

// Attach the array
oLbxglf:setArray( aGLList )
oLbxglf:aCols := {}

// Add the columns
ADD TO oLbxglf DATA ARRAY ELEMENT 3 HEADER "Account" SIZE 80 ALIGN LEFT
ADD TO oLbxglf DATA ARRAY ELEMENT 1 HEADER "Description" SIZE 150 ALIGN LEFT
ADD TO oLbxglf DATA ARRAY ELEMENT 2 HEADER "D/C" SIZE 50 ALIGN CENTER

// Provide the header gradient
oLbxglf:bClrGrad := { | lInvert | If( ! lInvert, { { 0.50,16776960,16777215 }, ;
{ 0.50,16777215,16776960 } }, { { 0.50,128,16777215 }, { 0.50,16777215,128 } } ) }
// Set the header and row heights
oLbxglf:nHeaderHeight := 30
oLbxglf:nRowHeight := 24
oLbxglf:nStretchCol( STRETCHCOL_WIDEST )

// Turn off horizontal scrolling
oLbxglf:lHScroll := .F.

// Set the styles
oLbxglf:nMarqueeStyle := MARQSTYLE_HIGHLROW
oLbxglf:nColDividerStyle := LINESTYLE_RAISED
oLbxglf:nRowDividerStyle := LINESTYLE_RAISED

oLbxglf:aCols[ 1 ]:cOrder = "A" // "A" for Ascending, "D" for Descending
oLbxglf:bSeek := { | c | SeekOnArray( oLbxglf, oLbxglf:aArrayData, c ) }

FOR nCCol := 1 TO LEN( oLbxglf:acols )
oLbxglf:aCols[nCCol]:nHeadStrAlign := AL_CENTER
NEXT

// Activate the dialog
ACTIVATE DIALOG oDlglf ON INIT ( oDlglf:center(wndmain()) )

RETURN( cGLRetVal )

Re: XBrowse Array Incremental Search

PostPosted: Wed Feb 10, 2010 11:28 am
by Antonio Linares
Tim,

Here you have a working example:
Code: Select all  Expand view
#include "FiveWin.ch"
#include "XBrowse.ch"

function Main()

   local oDlg, oBrw
   local aValues := { { "one", "two", "three" }, { "four", "five", "six" }, { "seven", "eight", "nine" } }

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 1, 1 XBROWSE oBrw ARRAY aValues SIZE 185, 120
   
   oBrw:CreateFromCode()
   oBrw:bSeek := { | cKey | SeekOnArray( oBrw,, cKey ) }
   
   ACTIVATE DIALOG oDlg CENTER ;
      ON INIT ( oBrw:aCols[ 1 ]:cOrder := "D" )

return nil
 

Re: XBrowse Array Incremental Search

PostPosted: Wed Feb 10, 2010 11:41 am
by nageswaragunupudi
XBrowse's built-in incremental seek functionality is very good. But in case of Arrays this functionality works perfectly only when the Array columns are set sequentially from columns 1,2,3 ... The logic fails when the order of the columns is not sequential.

I propose this sample code to address Mr. Tim's problem:
Code: Select all  Expand view
#include "FiveWin.Ch"
#include "xbrowse.ch"

//------------------------------------------------------------------//

function Main()

   local oDlg, oBrw
   local aData := { ;
     { 4578, 'Sales',    'B012' }, ;
     {  234, 'Purchaes', 'B342'  }, ;
     {   75, 'Wages',    'C567'  }, ;
     { 1435, 'Freight',  'C203' } }


   DEFINE DIALOG oDlg SIZE 440,240 PIXEL
   @ 10,10 XBROWSE oBrw SIZE 200,100 PIXEL OF oDlg ;
      COLUMNS 3, 2, 1 ;
      HEADERS 'Account', 'Description', 'D/C' ;
      COLSIZES 80,150,80 ;
      ARRAY aData ;
      AUTOSORT ;
      ON DBLCLICK ( MsgInfo( oBrw:aRow[ 3 ] ), oDlg:End() )
      // Note: oBrw:aRow is shortcut for oBrw:aArrayData[oBrw:nArrayAt]

   oBrw:nStretchCol := 2

   //  Following three lines are needed till XBrowse is rectified
   oBrw:aCols[ 1 ]:cOrder := 'D'
   oBrw:aCols[ 1 ]:SetOrder()
   oBrw:bSeek  := { |c| ArrayIncrSeek( oBrw, aData, c ) }

   // < .. other browse settings .. >

   oBrw:CreateFromCode()

   ACTIVATE DIALOG oDlg CENTERED

return ( 0 )

//------------------------------------------------------------------//

function ArrayIncrSeek( oBrw, aData, cSeek )

   local nRow, nCol
   local cVal

   if ( nCol := AScan( oBrw:aCols, { |oCol| ! Empty( oCol:cOrder ) } ) ) > 0
      // following line is ommitted in TXBrowse source code
      nCol  := oBrw:aCols[ nCol ]:nArrayCol
      cSeek := Upper( cSeek )
      for nRow := 1 to Len( aData )
        if Upper( cValToChar( aData[ nRow ][ nCol ] ) ) = cSeek     // non-exact =
            oBrw:nArrayAt := nRow
            return .t.
         endif
      next nRow
   endif

return .f.

//------------------------------------------------------------------//
 

This code may be compiled to see that now the incremental seek works. After verifying, Mr. Tim may please add his specific functionality.

The above incremental seek function can be used generally for all array browses where the columns are not sequential.

If Mr. Antonio permits, I shall separately communicate my proposed fixes to the XBrowse code.

Re: XBrowse Array Incremental Search

PostPosted: Wed Feb 10, 2010 11:46 am
by Antonio Linares
Dear Rao,

many thanks for your great feedback and help as usual :-)

Re: XBrowse Array Incremental Search

PostPosted: Thu Feb 11, 2010 9:00 pm
by TimStone
Thank you. I had noted that the behavior was not working correctly when the columns were not in order. I look forward to the fix in xBrowse.

The interim solution works great. Thanks.

Re: XBrowse Array Incremental Search

PostPosted: Wed Mar 03, 2010 11:07 am
by anserkk
Hi,

Is this problem solved ?

As Per Antonio, Whats new in FWH 10.2 wrote:* Fix: XBrowse.prg: Incremental seek on Arrays works only when columns are added sequentially and that too in the
SetArray method. Now fixed. Incremental seek works irrespective of the order of the array columns if lAutoSort is
set to true in SetArray method.


I am getting compilation error When I tried the Sample Posted above by Mr.Antonio
Code: Select all  Expand view

#include "FiveWin.ch"
#include "XBrowse.ch"

function Main()

   local oDlg, oBrw
   local aValues := { { "one", "two", "three" }, { "four", "five", "six" }, { "seven", "eight", "nine" } }

   DEFINE DIALOG oDlg SIZE 400, 300

   @ 1, 1 XBROWSE oBrw ARRAY aValues SIZE 185, 120
   
   oBrw:CreateFromCode()
   oBrw:bSeek := { | cKey | SeekOnArray( oBrw,, cKey ) }
   
   ACTIVATE DIALOG oDlg CENTER ;
      ON INIT ( oBrw:aCols[ 1 ]:cOrder := "D" )

return nil


Compilation Error :=
Unresolved external '_HB_FUN_SEEKONARRAY' referenced from D:\FwhTest\Test.Obj


When I changed the line to
Code: Select all  Expand view
oBrw:bSeek := { | cKey | oBrw:SeekOnArray( oBrw,, cKey ) }


Then there are no compilation errors, but I get the following Run time error

Application
===========
Path and name: D:\FWHTest\test.exe (32 bits)
Size: 1,769,984 bytes
Time from start: 0 hours 0 mins 2 secs
Error occurred at: 03/03/10, 16:25:59
Error description: Error BASE/1004 Message not found: TXBROWSE:SEEKONARRAY
Args:

Stack Calls
===========
Called from: .\source\function\HARBOUR.PRG => _CLSSETERROR(166)
Called from: .\source\classes\XBROWSE.PRG => TXBROWSE:SEEKONARRAY(6980)
Called from: test.prg => (b)MAIN(14)
Called from: .\source\classes\XBROWSE.PRG => TXBROWSE:SEEK(5383)
Called from: .\source\classes\XBROWSE.PRG => TXBROWSE:KEYCHAR(2185)
Called from: => TWINDOW:HANDLEEVENT(0)
Called from: .\source\classes\CONTROL.PRG => TCONTROL:HANDLEEVENT(1464)
Called from: .\source\classes\XBROWSE.PRG => TXBROWSE:HANDLEEVENT(10470)
Called from: .\source\classes\WINDOW.PRG => _FWH(3378)
Called from: => DIALOGBOXINDIRECT(0)
Called from: .\source\classes\DIALOG.PRG => TDIALOG:ACTIVATE(273)
Called from: test.prg => MAIN(17)


Am I doing anything wrong ?

With Mr.Rao's sample, incremental search on Array using xBrowse is working fine.

Regards
Anser

Re: XBrowse Array Incremental Search

PostPosted: Wed Mar 03, 2010 12:29 pm
by nageswaragunupudi
It is working fine for me with 10.2.

I advise you to keep in mind that when we specify AUTOSORT clause in the XBROWSE command or specify lAutoSort as parameter in any of the set methods like SetRDD, SetADO, SetODBF, SetArray, XBrowse automatically constructs bSeek codeblock. This default codeblock is generally much superior to what we can ourselves construct in our program. It is always desirable that we depend on the default codeblock created by XBrowse and not to disturb it by ourselves assigning our own codeblock to bSeek, unless we want an unconventional behavior.

In case of arrays, the SeekOnArray function of XBrowse had a minor bug till version 10.1 which effects array browses not having columns in serial from 1,2... Hence the need to have our own function.

SeekOnArray function in XBrowse is static function. Therefore it is not available for linking in our programs.

Mr. TimStone said
oLbx:bSeek := { |c| oDbf:Seek( c ) }

My personal advice is not to assign any codeblock to bSeek. The default codeblock generated by xBrowse is much better.

Re: XBrowse Array Incremental Search

PostPosted: Wed Mar 03, 2010 12:32 pm
by nageswaragunupudi
Mr. Anser
With Mr.Rao's sample, incremental search on Array using xBrowse is working fine.

This is the one you should have for versions upto 10.1. Even this is needed only if your array browse is not columns 1,2,3 ... in serial order.

You may even replace SeekOnArray function inside xbrowse.prg and recompile.

Re: XBrowse Array Incremental Search

PostPosted: Wed Mar 03, 2010 1:02 pm
by anserkk
Dear Mr.Rao,

Mr.Rao wrote:SeekOnArray function in XBrowse is static function. Therefore it is not available for linking in our programs.

This was the reason for the RunTime error. I misunderstood that Mr.Antonio was referring to the function SeekOnArray() which was available in xBrowse.Prg. As I received a compilation error, I assumed that Mr.Antonio must have missed the oBrw: in the sample code and changed the code to oBrw:bSeek := { | cKey | oBrw:SeekOnArray( oBrw,, cKey ) } which gave run time error. :oops:

Mr.Rao wrote:My personal advice is not to assign any codeblock to bSeek. The default codeblock generated by xBrowse is much better.


I was of the impression that oBrw:bSeek should be provided in our code for incremental search to work.

I removed the oBrw:bseek and let xBrowse to do the work for me and now everything is working as expected. Perfect !!! :)

Thank you very much. :)

Regards
Anser