Page 1 of 2

XBrowse. Bug in row painting

Posted: Sun Jan 13, 2008 2:27 am
by nageswaragunupudi
Mr Antonio

In some circumstances, when the user selects a browse with a mouse click on a row ( say 4th row ) the xbrowse paints the first row information on the clicked row. Thereafter with arrow keys we can not go up but we can go down. 2nd row is painted on 5th row and so on. Please see the screen shot for example:
Image
This is observed occasionally several times, but I could not reproduce it earlier. Now I have reproduced it in one case and give the code below. This code uses c:\fwh\samples\customer.dbf. The code creates necessary indexes and shows parent child scoped browses. The child table is related to the parent table with ordSetRelation. I also provided an option to choose either txbtowse or twbrowse. It can be seen the TWBrowse ( also TCBrowse) works perectly, and the problem is only with TXBrowse.

Code: Select all

#include 'fivewin.ch'
#include 'xbrowse.ch'

#define ORDREL

REQUEST DBFCDX

function main()

	OpenData()
	if alert( 'Choose Browse', { 'XBrowse', 'WBrowse' } ) == 1
   	testxbrw()
   else
   	testwbrw()
   endif
	close data

return nil

function testxbrw

local odlg, obrwSt, oBrw, ocol


	define dialog odlg size 800,340 pixel title 'TXBROWSE'

	@ 15,100 say 'XBROWSE CHILD TABLE' size 290,10 pixel of odlg center

	obrwSt := txbrowse():new(odlg)
	obrwSt:ntop 		:= 30
	obrwSt:nleft		:= 10
	obrwSt:nright		:= 80
	obrwSt:nbottom	   := 150
	obrwSt:calias 	:= 'state'

	ocol				:= obrwSt:addcol()
	ocol:cheader   := 'State'
	ocol:bstrdata	:= {||state->State}

   oBrwSt:SetRDD()
	obrwSt:createfromcode()


	obrw				:= txbrowse():new(odlg)
	obrw:ntop 		:= 30
	obrw:nleft		:= 100
	obrw:nright		:= 390
	obrw:nbottom	:= 150
	obrw:calias 	:= 'cust'

	ocol				:= obrw:addcol()
	ocol:cheader   := 'No'
	ocol:bstrdata	:= {||str( cust->(ordkeyno()),4)}


	ocol				:= obrw:addcol()
	ocol:cheader   := 'First'
	ocol:bstrdata	:= {||cust->first}

	ocol				:= obrw:addcol()
	ocol:cheader   := 'Last'
	ocol:bstrdata	:= {||cust->last}

	ocol				:= obrw:addcol()
	ocol:cheader   := 'City'
	ocol:bstrdata	:= {||cust->City}


	obrw:setRDD()
	obrw:CreateFromCode()


	@ 160,100 SAY eval( obrw:bKeyNo ) picture '9999' size 40,10 pixel of odlg right update
	@ 160,160 SAY eval( obrw:bKeyCount ) picture '9999' size 40,10 pixel of odlg right update

	oBrwSt:bChange	:= {||RowChange(oBrwSt, oBrw)}
	oBrw:bChange   := {||oDlg:update() }

	activate dialog odlg centered ;
		on init oBrwSt:SetFocus()

return nil


function testwbrw

local odlg, obrwSt, oBrw, ocol


	define dialog odlg size 800,340 pixel title 'TWBROWSE'

	@ 15,100 say 'XBROWSE CHILD TABLE' size 290,10 pixel of odlg center

	@ 30,10 LISTBOX oBrwSt ;
		FIELDS state->state ;
		HEADERS 'State' ;
		SIZE 50,120 PIXEL OF oDlg ;
		ALIAS 'STATE'

	@ 30,100 LISTBOX oBrw ;
		FIELDS str(cust->(Ordkeyno()),4), cust->first, cust->last, cust->city ;
		HEADERS 'No', 'First', 'Last', 'City' ;
		SIZE 290,120 PIXEL OF odlg ;
		ALIAS 'CUST'

	obrw:bLogicLen	:= {||cust->(ordkeycount())}

//	@ 160,100 SAY eval( obrw:bKeyNo ) picture '9999' size 40,10 pixel of odlg right update
	@ 160,160 SAY eval( obrw:blogiclen ) picture '9999' size 40,10 pixel of odlg right update


	oBrwSt:bChange	:= {||RowChange(oBrwSt, oBrw)}
	oBrw:bChange   := {||oDlg:update() }

	activate dialog odlg centered ;
		on init oBrwSt:SetFocus()

return nil



static function RowChange( oBrwSt, oBrw )

#ifndef ORDREL

	cust->(OrdScope(0,state->state))
	cust->(ordscope(1,state->state))

#endif

	cust->(dbgotop())
	oBrw:gotop()
	oBrw:Refresh(.t.)

	oBrw:oWnd:update()

return nil


static function OpenData

field state, city, first

local cfile	:= '\fwh\samples\customer'

	ferase( cfile + '.cdx' )
	use (cfile) exclusive via 'DBFCDX'
	index on state tag state unique
	index on state + city + first tag city
	use

	use (cfile) new alias state shared via 'DBFCDX'
	set order to tag state
	go top

	use (cfile) new alias cust shared via 'DBFCDX'
	set order to tag city
	go top

#ifdef ORDREL
//	state->( ordsetrelation( 'cust', {||state}, 'state' ) )
//      state->( dbgotop() )
//      scoped relation can be set either way

	state->( dbsetrelation( 'cust', { || State }, 'State', .t. ) )
	state->( dbgotop() )

#else

	cust->( ordscope( 0, state->state ) )
	cust->( ordscope( 1, state->state ) )
	cust->( dbgotop() )

#endif

return nil
This program can be compiled and run straight away. No setup is required as long as the customer.dbf exists in \fwh\samples folder.

On the left parent browse of States is presented and on the right child browse of customers in that State is presented. The problem comes when a customer (other than the first line) is selected with a mouse click in the child browse. WBrowse works perfectly but not XBrowse.
Note: XBrowse works well when scope is set on child table on bhchange of the parent browse, but fails with scoped relation. The problem is NOT with scoped relation, because WBrowse works well with scoped relations also. Same is the problem with DBFCDX and also ADS. Therefore the problem is with XBrowse only.

Posted: Sun Jan 13, 2008 3:27 am
by Antonio Linares
NageswaraRao,

In Class TWBrowse we had to implement a method UpStable() to get the right painting under certain circunstances. This method is not provided in Class TXBrowse.

Maybe thats what we need to fix it. I appreciate your feedback testing it with XBrowse, thanks

Posted: Sun Jan 13, 2008 3:32 am
by nageswaragunupudi
Mr Antonio

Thanks. Can you kindly look into this ? I faced this problem in some other circumstances also, but could not reproduce them. It is happening mostly when we bring a browse to focus by clicking on some row in the browse. I checked the lbuttondown method and could not figure out any solution.

Posted: Sun Jan 13, 2008 3:33 am
by nageswaragunupudi
In this case what is also intriguing me is why it is working when I set scope top and scope bottom in the bchange method, but failing when it is related with ordsetscope.

Posted: Sun Jan 13, 2008 4:06 am
by Antonio Linares
NageswaraRao,

Please check in Class TWBrowse from what methods the Method UpStable() is called.

Probably we have to implement it and call it in the same places from inside Class TXBrowse

Posted: Sun Jan 13, 2008 4:06 am
by nageswaragunupudi
Mr Antonio

I like to share with you some peculiar phenomenon I observed. Let me reproduce the relevant lines of code in lbuttondown method along with two debug lines of code I inserted:

Code: Select all

METHOD LButtonDown( nRow, nCol, nFlags ) CLASS TXBrowse
  < ... code .. >
     if nRowPos > 0 .or. nColPos > 0

      if ::nMarqueeStyle == MARQSTYLE_HIGHLROWMS
         if !GetKeyState( VK_CONTROL ) .and. !GetKeyState( VK_SHIFT )
            ::Select( 0 )
         endif
      endif
      ::DrawLine()
      if nRowPos > 0
//msginfo( str(nrowpos) + str(::nrowsel) ) // for debug
sysrefresh()  // for debug

         Eval( ::bSkip, nRowPos - ::nRowSel )
         ::nRowSel := nRowPos
         if ::bChange != nil
            Eval( ::bChange, Self )
         endif
      endif
      < ... code ... >
      ::DrawLine( .t. )
       < ...code .. >
1) When I uncomment the msginfo line above, it correctly shows the clicked row number and 1 as ::nrowsel. After the msginfo, the browse behaves correctly. Displays the clicked row correctly.
2) If i comment msginfo line and uncomment SysRefresh(), then also the clicked row is displayed correctly but the first row also remains highlighted

Posted: Sun Jan 13, 2008 4:09 am
by nageswaragunupudi
I shall check twbrowse, but meanwhile can you check the above posting? I am not able to understand why is it happening so.

Posted: Sun Jan 13, 2008 4:10 am
by Antonio Linares
MsgInfo() and SysRefresh() produce similar results as MsgInfo() uses a built-in SysRefresh() alike code (Win API code).

The difference is that MsgInfo() generates a WM_PAINT msg to the underlaying window, meanwhile SysRefresh() doesn't

Posted: Sun Jan 13, 2008 4:12 am
by nageswaragunupudi
Thanks. Paint method sets everything right. Now I understand.

Posted: Sun Jan 13, 2008 5:18 am
by nageswaragunupudi
Mr Antonio

1) Upstable method of TWBrowse is used only in bAdd block.
2) LButtonDown methods of both TWBrowse and TXBrowse seem to the same logically.

3) BUT THE PROBLEM IS APPARENTLY SOLVED
when I inntroduced SysRefresh() just above the first ::DrawLine() in the LButtonDown Method. ( Line No. 2174 in the source of FWH 8.01).

I do not see any logic why this should work, but it is working. Can you think about it and explain why does it remedy the problem?

Posted: Sun Jan 13, 2008 5:34 am
by Antonio Linares
NageswaraRao,

SysRefresh() allows to process pending Windows msgs so the proper processing order is done

Some of the methods or functions called before DrawLine() were not processed yet. SysRefresh() gave them priority

Posted: Sun Jan 13, 2008 5:46 am
by nageswaragunupudi
Mr Antonio

Do you think the problem is solved? I still feel uncomfortable because I could not see the real reason and found a solution for it.

Anyway for the time being shall we insert Sysrefresh() as a fix in the code?

Posted: Sun Jan 13, 2008 11:30 am
by Manuel Valdenebro
nageswaragunupudi wrote:Anyway for the time being shall we insert Sysrefresh() as a fix in the code?
Antonio,

May you confirm it is a FWH bug? In afirmative case, can you write what we must changing in xbrowse class ?

Posted: Sun Jan 13, 2008 11:33 am
by nageswaragunupudi
I think it is too early to say anything. In any case this does not give problem in many cases.

Mr Antonio will study the issue in detail and advise us suitably. Let is wait.

Posted: Mon Jan 14, 2008 4:24 pm
by Maurilio Viana
Friends,

I have the same problem in my xbrowses. I will test insert SysRefresh in that method and try. Any news I post here!

Thanks!!!
Maurilio