From: Paul D B on
Hi Grant,

Stephen Quinn wrote:

>
> Think about GLOBALS like you would about FILTERS
> - avoid wherever possible and if you 'think' you must use them
> re-think what your trying to do
>

Agree about the Globals but not about the filters.

A filter is just one of the possibilities we have to show only a subset of
records (and I'm pretty sure hundreds of people are using them).
There is nothing wrong with it but you have to be aware of the limitations
and performance problems. So it has to be used only under specific
circumstances.
The filter is evaluated at the client PC (unless you are using a
client:server solution such as ADS). So, when the file is big, that means a
lot of network traffic because the entire file will go over the networklink
and this again and again each time the file changes. Also, when the filter
returns only a few records out of a file with many records, it might take
ages (seconds) to filter them out of the file. You will end up with a very
sluggish data browser.
So: filter = OK, but file has to be small in size, not too many records ( a
few thousands at most), and has to return a fair subset of records. Never
use a filter to filter 1 record out of ten thousand others!

Other possibilities are:
- index scopes, which are extremely fast but less flexible than a filter (a
filter can be build with a complex expression). A scope can not always
"mimic" this, because it is a matter of having the appropriate index keys.
- (temporary) index order conditions: I am a fan of this, because it gives
you the flexibility of a filter (any complex expression) and the speed of a
scope. You could build a temporary index order with a condition, it will
take some time to build the file (but often as fast as applying a filter)
and then you got yourself a nice little index order that only contains the
records that match your condition.
- Fast Text Search
- SetRelation might in some cases also do what you want

So you see there are many approaches available, and you should pick the
appropriate one. How do you know this: trial and error <g> , just experiment
with it.
I have many applications where I started with filters, rewrote them to use
index scopes and ended up with temporary index orders conditions. Nothing
wrong with that, it is part of learning VO.

--
Paul


From: Paul D B on
Grant wrote:

>
> I was getting desperate when I asked about Global variables. Thank you
> to Geoff for his comments about proper use of the controlevent
> parameter. I was able to extract the field from the chosen record of
> the Customer data file by rewriting my CellDoubleClick method. Now I
> am able to access the field data as a string and was going to use this
> to set a filter. If there is abetter way please let me know. Here are
> the lines of code first to creat the first browser and then the
> CellDoubleClick callback method to get the desired customer field for
> the next browser :
>
> Method bBrowser_Customer class Shell
> LOCAL odtwBrowser AS dtwBrowser
> LOCAL odbsServer AS DBServer
> odbsServer := bDServer{"C:\CompanyFolder\Customer.dbf",,,
> GetRdd("C:\CompanyFolder\Customer.dbf")}
> odtw := dtwBrowser{SELF}
> odtwBrowser:Show()
> odtwBrowser:Use(odbsServer)
> and
> Method CellDoubleClick(oControlEvent) CLASS dtwBrowser
> LOCAL oBrowser AS JobWin
> LOCAL oCustBrowser as dtwBrowser
> LOCAL cFName AS USUAL
> LOCAL cFilter AS STRING
> LOCAL oControl := oControlEvent:Control
>
> cFilter := NULL_STRING
> oCustBrowser := oControEvent:Control
> cFName := oCustBrowser:Server:FieldGet(2)
> cFilter := cFName
>
> oBrowser := JobWin{SELF:Owner,,,{SELF,TRUE}}
> Works down to here. If I comment out the next 2 lines I get the second
> browser screen but contains all the records.
> oBrowser:SetFilter( cFilter )
> Something wrong here
> oBrowser:GoTop
> oBrowser:Show()
>
> Does this make sense? Would you not use a filter here? I'm trying to
> bend my head around using relationships but I'm a little lost. I want
> to pick a customer and then open a browser with a list of jobs done
> for that one customer and be able to edit, print, or create new jobs
> in this bbrowser screen.
>
> Thanks for your help
> Grant

Hi Grant (again)

I always make a Class variable for my DB servers. That way I have them at
hand everywhere, in each method of my datawindow. They never go out of
scope.

I will send you an example of a very small databrowser, which allows to
open a detailwindow when doubleclicking a record in which the record can be
updated and saved.

Might give you some inspiration


--
Paul


From: Stephen Quinn on
Grant

Your problem is your doing things out of order.

You should create DBServer classes (DBEditor) for every DBF you have in your
app and use it wherever you want to open the database.
Eg
CLASS MyDBServer INHERIT DBServer
// In this base class you can put your own methods & override the
base ones

CLASS Customer INHERIT MyDBServer
METHOD INIT( /*parameters*/ ) CUSTOMER
// Add the relevant details here
SELF:cDBFName := 'CUSTOMER.DBF'

Method bBrowser_Customer class Shell

LOCAL odtwBrowser AS dtwBrowser
LOCAL odbsServer AS DBServer

odbsServer := CUSTOMER{}

// You should pass in the opened Server to your window
odtw := dtwBrowser{SELF,, { odbsServer, {Array of Fields to
display} }

odtwBrowser:Show()

// you should assign the server in the postinit of the window
METHOD PostInit( p1,p2,p3 ) CLASS dtwBrowse

IF IsArray(p3) and ALen(p3) = 2
SELF:Server := p3[1]
SELF:oBB:Use( SELF:Server )
aFields := p3[2]
FOR i := 1 upto ALen( aFields )
oCol := bDataColumn{ aFields[i], // + the rest }
SELF:oBB:AddColumn(oCol )
NEXT
ENDIF

Method CellDoubleClick(oControlEvent) CLASS dtwBrowser

LOCAL oBrowser AS JobWin
LOCAL oCustBrowser as dtwBrowser
LOCAL cFName AS USUAL
LOCAL cFilter AS STRING
LOCAL oControl := oControlEvent:Control

cFilter := NULL_STRING
oCustBrowser := oControEvent:Control

// I suggest you use SYMBOL names instead of numeric values for the
fields
// Less chance of introducing a bug if you ever change the database
field order
cFName := oCustBrowser:Server:FieldGet( #FNAME )
// cFName := oCustBrowser:Server:FieldGet( 2 )
// cFilter := cFName

// I'm assuming the JobWin{} class openes the Jobs database and assigns
it to a bBrowser on the window

// Pass into the window the Filter criteria and set it in the postinit
oBrowser := JobWin{SELF:Owner,,,{SELF,TRUE, cFName } }
oBrowser:Show()

The way your doing this will make it difficult to set a relationship like I
showed in an earlier post.
If you open ALL databases you require at the same time setting relationships
is a piece of cake.

What I usually did is open ALL databases in the basewindow:postint() put
them into an array and pass that array around to any other window that
needed access to the servers. All relationships/scopes/etc... were done in
the base window not by any new window that was opened
Eg
anArrayOfServers := ArrayNew(5)
anArrayOfServers[1] := Customers{}
anArrayOfServers[2] := Orders{}
anArrayOfServers[3] := Jobs{}
anArrayOfServers[4] := Suppliers{}
anArrayOfServers[5] := Invoices{}

CYA
Steve


First  |  Prev  | 
Pages: 1 2 3
Prev: Simple email sample
Next: Graphics4VO to vulcan