Alaska Software Inc. - Using fieldblock as a datalink
Username: Password:
AuthorTopic: Using fieldblock as a datalink
Scott KriseUsing fieldblock as a datalink
on Fri, 20 Oct 2006 11:04:31 -0400
I am converting a text based data entry screen to a GUI screen, and I am 
flip-flopping between setting the datalink for my entry field as a variable 
(like I did in clipper), or to tie it directly to a database field using a 
fieldblock. I am using the tdxget function from top-down to do my gets, and 
I can see definite advantages to using fieldblocks, however I am running 
into one specific problem doing it that way. If the I use the fieldblock 
logic and start to ADD a record to the table, one of my first steps in the 
ADD button logic is to do a dbappend()...which of course adds a blank record 
to my table. If the user updates the information and clicks my SAVE 
button....I'm good...If they decide not to update and hit my CANCEL button 
to exit without saving...I'm good (I just delete the blank record they 
created), however if something unusual happens and they do an END TASK of my 
application from the task manager, then I am stuck with that blank record 
being left out in my table.

If I stick with using varibles as the datalink for my gets, I avoid this 
problem, because I do the dbappend immediately before writing the variables 
to the table, so this problem will never occur.

I guess I'm wanting some opinions on how everyone deals with this in their 
apps.

Thanks,

Scott
Rodd GrahamRe: Using fieldblock as a datalink
on Fri, 20 Oct 2006 13:04:55 -0500
Scott,

While I personally do something completely different, your strategy can be 
altered as follows:

ADD:

append blank
delete
dbcommit()

SAVE:

recall
unlock

CANCEL:

unlock

Rodd

"Scott Krise" <dstine_cti@alltel.net> wrote in message 
news:78f1c6b9$69578232$840f1@news.alaska-software.com...
>I am converting a text based data entry screen to a GUI screen, and I am 
>flip-flopping between setting the datalink for my entry field as a variable 
>(like I did in clipper), or to tie it directly to a database field using a 
>fieldblock. I am using the tdxget function from top-down to do my gets, and 
>I can see definite advantages to using fieldblocks, however I am running 
>into one specific problem doing it that way. If the I use the fieldblock 
>logic and start to ADD a record to the table, one of my first steps in the 
>ADD button logic is to do a dbappend()...which of course adds a blank 
>record to my table. If the user updates the information and clicks my SAVE 
>button....I'm good...If they decide not to update and hit my CANCEL button 
>to exit without saving...I'm good (I just delete the blank record they 
>created), however if something unusual happens and they do an END TASK of 
>my application from the task manager, then I am stuck with that blank 
>record being left out in my table.
>
> If I stick with using varibles as the datalink for my gets, I avoid this 
> problem, because I do the dbappend immediately before writing the 
> variables to the table, so this problem will never occur.
>
> I guess I'm wanting some opinions on how everyone deals with this in their 
> apps.
>
> Thanks,
>
> Scott
>
>
>
James Loughner Re: Using fieldblock as a datalink
on Fri, 20 Oct 2006 15:31:28 -0400
I don't do the append until I hit the save button. To init the screen to
a new record I do DBGoBottom(), skip(1) then read the phantom record
into the screen.

I do all in class code (generated from the FD) so I have three methods I
almost always use and 1 ivar

the ivar is ::EditType  which can normally be "EDIT" or "NEW"

the methods are ::RefreshWND, ::Validate, and ::Save

METHOD RrefreshWND()
IF ::EditType = "NEW"
   (::DBarea)->(DBGoBottom())
   (::DBarea)->(DBSkip())
   AEval( ::edControls, {|o| o:setData() } )  read data into screen
   ......
ELSE
   AEval( ::edControls, {|o| o:setData() } )  read data into screen
   .....
ENDIF
RETURN Self

METHOD Save()
IF ::Validate()
   IF (::DbArea)->(DBSeek(keyvalue))
      (::DbArea)->(DBRLock())
   ELSE
      (::DbArea)->(DBAppend())
   ENDIF
   AEval( ::edControls, {|o| o:getData() } )  save data from screen
   ....
   ::Destroy()
ENDIF
RETURN Self


note ::edControls is an array with reference to all XBPs that have a
Datalink assigned

Jim



Scott Krise wrote:
> I am converting a text based data entry screen to a GUI screen, and I am 
> flip-flopping between setting the datalink for my entry field as a variable 
> (like I did in clipper), or to tie it directly to a database field using a 
> fieldblock. I am using the tdxget function from top-down to do my gets, and 
> I can see definite advantages to using fieldblocks, however I am running 
> into one specific problem doing it that way. If the I use the fieldblock 
> logic and start to ADD a record to the table, one of my first steps in the 
> ADD button logic is to do a dbappend()...which of course adds a blank record 
> to my table. If the user updates the information and clicks my SAVE 
> button....I'm good...If they decide not to update and hit my CANCEL button 
> to exit without saving...I'm good (I just delete the blank record they 
> created), however if something unusual happens and they do an END TASK of my 
> application from the task manager, then I am stuck with that blank record 
> being left out in my table.
> 
> If I stick with using varibles as the datalink for my gets, I avoid this 
> problem, because I do the dbappend immediately before writing the variables 
> to the table, so this problem will never occur.
> 
> I guess I'm wanting some opinions on how everyone deals with this in their 
> apps.
> 
> Thanks,
> 
> Scott
> 
> 
>
Scott KriseRe: Using fieldblock as a datalink
on Thu, 26 Oct 2006 08:24:20 -0400
Jim,

Thanks...this is what I was looking for. Actually, I tried this approach 
earlier...but ran into some problems with it. It's working the way I want it 
to now...I think I had another issue that caused my problems before.

Thanks for your input (as well as the others who replied).

Scott
Joe Carrick Re: Using fieldblock as a datalink
on Sat, 21 Oct 2006 09:27:08 -0700
I use fieldWBlock() instead.  It's better because it identifies the work 
area and allows for the possibility that the current work area is not 
the one you are linking the data to.

-Joe

Scott Krise wrote:
> I am converting a text based data entry screen to a GUI screen, and I am 
> flip-flopping between setting the datalink for my entry field as a variable 
> (like I did in clipper), or to tie it directly to a database field using a 
> fieldblock. I am using the tdxget function from top-down to do my gets, and 
> I can see definite advantages to using fieldblocks, however I am running 
> into one specific problem doing it that way. If the I use the fieldblock 
> logic and start to ADD a record to the table, one of my first steps in the 
> ADD button logic is to do a dbappend()...which of course adds a blank record 
> to my table. If the user updates the information and clicks my SAVE 
> button....I'm good...If they decide not to update and hit my CANCEL button 
> to exit without saving...I'm good (I just delete the blank record they 
> created), however if something unusual happens and they do an END TASK of my 
> application from the task manager, then I am stuck with that blank record 
> being left out in my table.
> 
> If I stick with using varibles as the datalink for my gets, I avoid this 
> problem, because I do the dbappend immediately before writing the variables 
> to the table, so this problem will never occur.
> 
> I guess I'm wanting some opinions on how everyone deals with this in their 
> apps.
> 
> Thanks,
> 
> Scott
> 
> 
>
Garry Allen Re: Using fieldblock as a datalink
on Thu, 26 Oct 2006 13:09:36 -0400
Hi Scott
    I (still) use variables for several reasons. The main one is that 
everything I do is class based. If e.g. I have a Person Class the Init 
procedure takes a parameter lNew. If lNew is True then I set defaults 
for all its properties (address, phone, etc.). This allows me to have 
procedures which may set e.g. the City field to some predefined value 
(as opposed to the ghost record which fills everything with blanks, etc).
If lNew is False then I load all the properties from the current record 
including an nRec property which is the record # in the file or 0 if a 
new record is to be created. My Save routine uses this to determine if 
it should do a dbappend or goto that record, lock it, and update it.
One other advantage of this approach is that the Person 'object' can be 
passed to other routines (e.g. a function to print an address label) as 
a single variable. Another is that I can have an inherited class 
override the Save method and do things like store the address in a 
totally different file.
Garry

Scott Krise wrote:
> I am converting a text based data entry screen to a GUI screen, and I am 
> flip-flopping between setting the datalink for my entry field as a variable 
> (like I did in clipper), or to tie it directly to a database field using a 
> fieldblock. I am using the tdxget function from top-down to do my gets, and 
> I can see definite advantages to using fieldblocks, however I am running 
> into one specific problem doing it that way. If the I use the fieldblock 
> logic and start to ADD a record to the table, one of my first steps in the 
> ADD button logic is to do a dbappend()...which of course adds a blank record 
> to my table. If the user updates the information and clicks my SAVE 
> button....I'm good...If they decide not to update and hit my CANCEL button 
> to exit without saving...I'm good (I just delete the blank record they 
> created), however if something unusual happens and they do an END TASK of my 
> application from the task manager, then I am stuck with that blank record 
> being left out in my table.
> 
> If I stick with using varibles as the datalink for my gets, I avoid this 
> problem, because I do the dbappend immediately before writing the variables 
> to the table, so this problem will never occur.
> 
> I guess I'm wanting some opinions on how everyone deals with this in their 
> apps.
> 
> Thanks,
> 
> Scott
> 
> 
>
Clayton Jones Re: Using fieldblock as a datalink
on Thu, 26 Oct 2006 18:30:42 -0400
Hello Scott,

>If I stick with using varibles as the datalink for my gets, I avoid this 
>problem, because I do the dbappend immediately before writing the variables 
>to the table, so this problem will never occur.

It really isn't all that different.  The reason we used vars in
Clipper was to temporarily store the data.  In GUI we do exactly the
same thing but the Get object is the storage mechanism.  It does the
job the vars used to do.  The basic logic can be the same, as Jim
said: wait until the save button before moving data fron the Gets to
the table.

As for passing data to sub routines, the same applies, we just do it a
slightly different way:

  Clipper: myValidFunc(@cGetVar)  

  Xpp: myValidFunc(oGet)

More specifically in Top-Down, the bValid codeblock has the Get passed
to it, represented by o here

  bValid := {|o|  myValidFunc(o) }



Same for altering the edited value in that sub routine

 Clipper: 
 FUNCTION myValidFunc(cGetVar)
 xGetVar := 'abc'

 Xpp:
 FUNCTION myValidFunc(oGet)
 oGet:setData('abc')



All the same logic applies, just the mechanism is a bit different.
Using vars can be done, but it's just added and unnecessary work and
in some cases can make it more difficult to take advantage of the
powerful capabilities offered by OOP.

IMO you'll be doing yourself a favor in the long run by biting the
bullet and leave the vars behind.


Regards,
Clayton

Clayton Jones   www.cjcom.net 
 Top-Down Library for Xbase++
 X-DBU Database Utility   
 X-MEMO Memo Field Replacement
Scott KriseRe: Using fieldblock as a datalink
on Fri, 27 Oct 2006 14:55:17 -0400
Hi Clayton,

Yes...I agree. Since I originally posted this question, I have bitten the 
bullet and got rid of the variables. You are right that it really isn't that 
much different than using variables, and it does offer some some added 
benefits I didn't have before.

The one thing I ran into that I did manage to work around (pretty 
ungracefully), but I'd like some suggestions on was what to do when you have 
some fields on the screen you want the user to be able to update...and 
others where you just want them to be able to view it. The way I have my 
system working now is that I set up my gets like this:

oRMDesc := tdXget( 
7.25,22.50,fieldblock('MAT_DESC'),oDa,50,oGetScreen,replicate("!",50))
oRMDesc:setData()
aadd(aGets,oRMDesc)
oRMDesc:aHelpmsg := {oStatbar,padc("Enter A Description Of The Raw 
Material", 235)}

Then I use the aeval as follows when I'm ready to let them update:

aeval(aGets,{|x,i| ;
         aGets[i]:editable := .T. ,;   set to edit mode
         aGets[i]:configure()     ,;   reconfigure
         aGets[i]:setData()       ,;   refresh
         aGets[i]:cOriginal := aGets[i]:editBuffer() })

So my question is, how should I handle the database fields that I want them 
to see, but not be able to update? I like keeping all the fields on my 
screen within my aGets array so I can easily change the whole screen from 
editable to un-editable, etc...so what I'm doing is immediatly after I 
perform the aeval() to set everthing to editable, I go back through change 
the uneditable ones manually. Is there a better way to do this?

Scott
Rodd Graham Re: Using fieldblock as a datalink
on Sat, 28 Oct 2006 00:27:04 +0000
Scott,

FUNCTION ReadOnlyFieldWBlock( cFieldName, cnArea )
   LOCAL cBlock := "{|x| ", bBlock, nArea := Select()

   DbSelectArea( cnArea )
   IF FieldPos( cFieldName ) <> 0
      IF Valtype( cnArea ) == "C"
         cBlock += cnArea+ '->'
      ELSE
         cBlock += "(" +LTrim(Str(cnArea))+ ")->"
      ENDIF
      cBlock += "(FIELD->"+cFieldName+") }"
      bBlock := &(cBlock)
   ENDIF
   DbSelectArea( nArea )

RETURN bBlock

Note that I would always use a character alias and never a numeric work area 
number since it will properly work across thread boundaries in the event 
that the same table is open in different work areas in each thread.

FYI: Original FieldWBlock() function from Alaska (source\SYS\Blocks.prg)

****************************************************************************
* Data code block for fields in a given work area
****************************************************************************
FUNCTION FieldWBlock( cFieldName, cnArea )
   LOCAL cBlock := "{|x| ", bBlock, nArea := Select()

   DbSelectArea( cnArea )
   IF FieldPos( cFieldName ) <> 0
      IF Valtype( cnArea ) == "C"
         cBlock += cnArea+ '->'
      ELSE
         cBlock += "(" +LTrim(Str(cnArea))+ ")->"
      ENDIF
      cBlock += "(IIf(x==NIL,FIELD->"+cFieldName+","+ ;
                            "FIELD->"+cFieldName+":=x)) }"
      bBlock := &(cBlock)
   ENDIF
   DbSelectArea( nArea )

RETURN bBlock

Rodd

> Hi Clayton,
> 
> Yes...I agree. Since I originally posted this question, I have bitten
> the bullet and got rid of the variables. You are right that it really
> isn't that much different than using variables, and it does offer some
> some added benefits I didn't have before.
> 
> The one thing I ran into that I did manage to work around (pretty
> ungracefully), but I'd like some suggestions on was what to do when
> you have some fields on the screen you want the user to be able to
> update...and others where you just want them to be able to view it.
> The way I have my system working now is that I set up my gets like
> this:
> 
> oRMDesc := tdXget(
> 7.25,22.50,fieldblock('MAT_DESC'),oDa,50,oGetScreen,replicate("!",50))
> oRMDesc:setData()
> aadd(aGets,oRMDesc)
> oRMDesc:aHelpmsg := {oStatbar,padc("Enter A Description Of The Raw
> Material", 235)}
> Then I use the aeval as follows when I'm ready to let them update:
> 
> aeval(aGets,{|x,i| ;
> aGets[i]:editable := .T. ,;   set to edit mode
> aGets[i]:configure()     ,;   reconfigure
> aGets[i]:setData()       ,;   refresh
> aGets[i]:cOriginal := aGets[i]:editBuffer() })
> So my question is, how should I handle the database fields that I want
> them to see, but not be able to update? I like keeping all the fields
> on my screen within my aGets array so I can easily change the whole
> screen from editable to un-editable, etc...so what I'm doing is
> immediatly after I perform the aeval() to set everthing to editable, I
> go back through change the uneditable ones manually. Is there a better
> way to do this?
> 
> Scott
>
Clayton Jones Re: Using fieldblock as a datalink
on Fri, 03 Nov 2006 09:52:48 -0500
Hello Scott,

Sorry to take so long to reply, has been frantic around here lately.


>oRMDesc := tdXget( 
>7.25,22.50,fieldblock('MAT_DESC'),oDa,50,oGetScreen,replicate("!",50))
>oRMDesc:setData()
>aadd(aGets,oRMDesc)
>oRMDesc:aHelpmsg := {oStatbar,padc("Enter A Description Of The Raw 
>Material", 235)}
>
>Then I use the aeval as follows when I'm ready to let them update:
>
>aeval(aGets,{|x,i| ;
>         aGets[i]:editable := .T. ,;   set to edit mode
>         aGets[i]:configure()     ,;   reconfigure
>         aGets[i]:setData()       ,;   refresh
>         aGets[i]:cOriginal := aGets[i]:editBuffer() })
>
>So my question is, how should I handle the database fields that I want them 
>to see, but not be able to update? I like keeping all the fields on my 
>screen within my aGets array so I can easily change the whole screen from 
>editable to un-editable, etc...so what I'm doing is immediatly after I 
>perform the aeval() to set everthing to editable, I go back through change 
>the uneditable ones manually. Is there a better way to do this?

What you are doing here with Xgets is mimicing what the DE system
already does - turn the Gets on and off.  That is the fundamental
difference between Xgets and DEgets.  The way the DE system handles
this is to use multiple arrays of Gets.  aAllGets is used for updates.
aEditGets is for those Gets you want to edit.  

You could do the same here.  For example, if oGet3 is not to be edited
it is added only to aAllGets.  If oGet4 is to be edited it is added to
both arrays.  The aeval() above would operate only on aEditGets.  The
aeval used for updates would operate on aAllGets.  

The beauty of this approach is that these arrays can be passed around
or assigned to different routines.  If you look at the DEkeys()
function you'll see how any number of Get arrays can be used.  The one
needed for the occasion is handed off to the "edit engine".  I had a
complex DE window once that had six different subsets of Gets for
specialized editing.  There were six different arrays besides aAllGets
(aAllGets was used for navigational refreshing and for the AddRec
routine).

BTW, you are not increasing memory or resource use much by doing these
multiple arrays.  The arrays don't hold copies of the Get objects, but
are merely pointers to the Gets.  There is only one instance of each
Get in memory.

I hope this helps.


Regards,
Clayton

Clayton Jones   www.cjcom.net 
 Top-Down Library for Xbase++
 X-DBU Database Utility   
 X-MEMO Memo Field Replacement
Scott KriseRe: Using fieldblock as a datalink
on Fri, 10 Nov 2006 09:24:03 -0500
Thanks Clayton.