FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour xBrowser How to display customers/city a kind of treeview
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 09:38 AM
I tried to display – this is easy and working- but if you skip than this seems to be much work.

Is there somewhere a sourcecode example showing how to do such a browse?

For example: I would like to show all customers if there are more than one customer in a city the city is only shown once
(a kind of treeview)


Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 01:42 PM
For arrays I do like this :
      oCol:bStrData := {||iif( oBrw:nArrayAt > 1 .and. aArray[oBrw:nArrayAt][1] == aArray[oBrw:nArrayAt-1][1], space(10),aArray[oBrw:nArrayAt][1] )}

I commonly do this for arrays and ado recordsets. We can also do it for DBFs but the code depends on your specifc case.

Ideally we would like if no lines are painted within a group. This can be done but needs one more data item in the column object and some change in the browse's paint method
Regards



G. N. Rao.

Hyderabad, India
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 03:51 PM
Hello NageswaraRao,

Thank you for your code.
I tested and it works as suspected for arrays.


Am I right that if you use dbf-files aArray can’t be used?

Do I have to make an own array parallel to get this functionality?

To test I tried with dbf files - I think it is similar to your code but hard coded - I used:

STATIC cCity
func bStrDataFIELD_CITY()
local cTEmpCity := _FIELD->CITY
IF cCity = cTEmpCity
cTEmpCity := " "
else
cCity := _FIELD->CITY
ENDIF
return cCity

But if you skip this does not work and I thought to fill an array parallel with the current scope.
Could you imagine if this will work.

What is the reason why xBrowse distinguish between array and dbf-file. If you look at other languages they make a recordset or a dataadapter and bind the browser to this.
Regards,
Otto
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 04:24 PM

The main requirement is to test whether the current field value = the previous records fieldvalue.

You can achieve this in different ways. What you do may just depend on dbf size, index key and so on.

If the dbf is not too large, and confident that other users will not change during the session, one way to do this may be like this.

Traverse the DBF and store the record numbers of the first occurance of the keyfield in an array. Then
bStrData := {|| iif( ascan( recno(), aUniques ) == 0, fieldget(1), space( <len> ) }

There are many other ways.
Few examples:
you can have a udf to look up previous value and return if the current value is a repeat.

If you create a compound index in a suitable way you can self relate the dbf so that the child points to prev record in the index.

You choose the optimal method depending on each specific case.

Regards



G. N. Rao.

Hyderabad, India
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 04:27 PM

Sorry, I edited during you answered.
Regards,
Otto

Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 04:42 PM

NageswaraRao,

Thank you for you answer. I thought to fill a temp-array in this part
of xBrowser and then to access this array.

METHOD Paint() CLASS TXBrowse

do while nRowPos <= nMaxRows
// We must also paint some times after the last visible column

---> fill the temp array
...
Do you think this could be possible?
Regards,
Otto

Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 04:51 PM

My personal advise is not to change FWH xBrowse code. Even if you change please do not change Paint method for handling values.

Please try to manage it within our application code. I suggested some ways of doing it for dbf tables.

Regards



G. N. Rao.

Hyderabad, India
Posts: 6983
Joined: Fri Oct 07, 2005 07:07 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 05:46 PM

Hello NageswaraRao,

I thought doing that you don't lose much speed because the array will only be a few records < 50 ?.
Best regards,
Otto

Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 08:54 PM

Otto,

Here is an idea. Instead of using the CITY field in the browse use a function. Then use bSkip to pass the city field to the function. Inside the function you need a static var, cLastCity. Using this var return the city name of the current record only when it is not the same as cLastCity, otherwise just return nil or a space.

The ideal way to do this is to create a customer class as a subclass from TData, then add a method to handle the above. Otherwise I would suggest using a static function.

James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 09:25 PM

Otto,

There is a problem with my idea above. I have used this for reports but with browses users can move backwards. This makes it more complicated. For each record movement, you would have to determine if you are at the first occurance of the city or not. So, you would have to skip in the appropriate direction (forward or back) one extra record to determine this, then skip back to the original record. It's more complicated, but I still think it could be done.

James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 10:23 PM
Otto,

Here is a working example using a customer class as a subclass of TData. I have also shown the city field so you can see it is working. This is not very efficient as it requires three disk reads to display each record. I think it could be done using static vars to eliminate the extra disk reads.



Here is the code:

/*
Purpose: Display city name only on first occurance in a browse
Date   : 12/23/2007
Author : James Bott, jbott@compuserve.com
Note   : Requires TData class
*/

#include "fivewin.ch"


function main()
   local oWnd, oLbx, oCustomer

   use customer exclusive
   index on upper(city) to cust2
   use


   oCustomer:= TCustomer():new()
   //oCustomer:setOrder(2)
   oCustomer:gotop()

   define window oWnd title "Test City Group"

   @0,0 listbox oLbx fields oCustomer:firstCity(), oCustomer:city, oCustomer:last, oCustomer:first;
      headers "City","City","Last","First";
      sizes 100,100,100,100;
      alias oCustomer:cAlias;
      of oWnd

   oLbx:bSkip := {| nRecs | oCustomer:skipper( nRecs ) }

   oWnd:oClient:= oLbx

   activate window oWnd

   oCustomer:end()

return nil

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

class TCustomer from TData
   method new
   method firstCity
endclass

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

method new()
   super():new(,"customer")
   ::use()
   //::addIndex("cust1")  // primary key
   ::addIndex("cust2") // city
   ::gotop()
return self

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

method firstCity()
   local cPrev,cCurrent
   cCurrent:= ::city
   ::skip(-1)
   cPrev:= ::city
   ::skip()
return if( cCurrent = cPrev, "", cCurrent)

// end
FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
xBrowser How to display customers/city a kind of treeview
Posted: Sun Dec 23, 2007 10:52 PM

I have looked at this some more, and now I don't think you can do this without three record reads. You have to know what the city for the previous record is and you can't use static vars to keep track of this since you may be moving forward or backward in the browse. When I refer to the "previous" record I don't mean the last record read, but the record before the current record in the current order. So you have to do a skip(-1) to find this, then skip back to your original location.

In a browse the user can skip forward or backward one or more records at a time, so there is no way to keep track of the "previous" record--you just have to read it.

This means the browse will require three times the disk traffic as a browse without city groups. Only testing will tell if this is useable.

Regards,
James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
xBrowser How to display customers/city a kind of treeview
Posted: Mon Dec 24, 2007 01:52 AM

Thats the reason I did not propose a similar approach. It it is a small table I would first scan and store recno's of the records to display. If it is large I would create an index like city + str(recno(),10,0) and set relation to the same table with prev rec. Then the condition is if main->city == child-city show blank else show city

Or we can use a UDF. Degrades performance. function is something like
func isRepeat
local thisval := field->city
local thisrec :=recno()
local lsame := .f.

dbskio(-1)
lsame := ( !bof() .and. thisval == field->city)
dbgoto(thisrec)

return lsame

Regards



G. N. Rao.

Hyderabad, India
Posts: 4840
Joined: Fri Nov 18, 2005 04:52 PM
xBrowser How to display customers/city a kind of treeview
Posted: Mon Dec 24, 2007 02:26 AM

Nageswara,

> If it is large I would create an index like city + str(recno(),10,0) and set relation to the same table with prev rec. Then the condition is if main->city == child-city show blank else show city.

Wouldn't this also require multiple disk reads, one for the main table and one for child table? Perhaps this is only requires two reads instead of three?

James

FWH 18.05/xHarbour 1.2.3/BCC7/Windows 10
Posts: 10733
Joined: Sun Nov 19, 2006 05:22 AM
xBrowser How to display customers/city a kind of treeview
Posted: Mon Dec 24, 2007 02:54 AM

Yes, true. But lesser client server traffic. Reading related tables is faster than the program sending requests to read.

Regards



G. N. Rao.

Hyderabad, India