Thursday, 5 December 2013
Tuesday, 17 April 2012
Been a While, but Not Been Quiet!
Just noticed it's been a while since I posted up here!
Trouble is, in the past two years I've been working with Pete Tabord in 'Team Ffenics' as I call us.
most of my writing time has been focused on starting and building a Ffenics Knowledgebase, which you can check out at:
http://www.ffenics.com/learn/mastering/knowledgebase/index.php?action=show.
I've continued to write my newsletter -- check out the archives here:
http://archive.aweber.com/n10net
Or subscribe to it via the sign-up from on my home page:
http://www.n10net.com
And Ffenics has its own newsletter as well -- cunningly called The Ffenician (it's a pun-a-minute with me!). Archive here:
http://archive.aweber.com/ffenics
and sign-up here:
http://www.ffenics.com
I'm also heads-down into coding Ffenics, ready for a new version which we hope to get out in time for the London Olympics. Not least of which because I have tickets for hockey and cycling ...
A related London event -- and again back to Ffenics -- is that we have a stand at the Business Start-up show in the ExCeL centre, London, May 17th-18th. And the week after that, I am running another Fforward with Ffenics workshop, in Convent Garden (well, slightly north of the actual tube station). Interested? Click here for details and to express your interest:
http://n10net.com/FfenicsWorkshopLondon2012.aspx
Trouble is, in the past two years I've been working with Pete Tabord in 'Team Ffenics' as I call us.
most of my writing time has been focused on starting and building a Ffenics Knowledgebase, which you can check out at:
http://www.ffenics.com/learn/mastering/knowledgebase/index.php?action=show.
I've continued to write my newsletter -- check out the archives here:
http://archive.aweber.com/n10net
Or subscribe to it via the sign-up from on my home page:
http://www.n10net.com
And Ffenics has its own newsletter as well -- cunningly called The Ffenician (it's a pun-a-minute with me!). Archive here:
http://archive.aweber.com/ffenics
and sign-up here:
http://www.ffenics.com
I'm also heads-down into coding Ffenics, ready for a new version which we hope to get out in time for the London Olympics. Not least of which because I have tickets for hockey and cycling ...
A related London event -- and again back to Ffenics -- is that we have a stand at the Business Start-up show in the ExCeL centre, London, May 17th-18th. And the week after that, I am running another Fforward with Ffenics workshop, in Convent Garden (well, slightly north of the actual tube station). Interested? Click here for details and to express your interest:
http://n10net.com/FfenicsWorkshopLondon2012.aspx
Sunday, 18 July 2010
Disagreeing with the Past
I've been trawling through past articles and snippets that I've written, and came across this letter to the new editor of Dialogue in which I disagreed with an article in the previous issue.
I don't remember ever sending this! But since I don't disagree with what I wrote then (this was April 2002), and since I still see DOS-like code permeating DfW and Ff apps, I'll print it now.
You'll have to imagine the article I was replying to, unless you have a copy of that issue.
Your turn to disagree...
I don't remember ever sending this! But since I don't disagree with what I wrote then (this was April 2002), and since I still see DOS-like code permeating DfW and Ff apps, I'll print it now.
You'll have to imagine the article I was replying to, unless you have a copy of that issue.
Dear Editor,
I beg to differ with some points made in the article on page 39 of the Winter 2001 Dialogue discussing DfW procedure rules.
“Where possible, fields that sort or group should be at the top of the procedure.”
This is misleading.
The position of grouping in a DQL determines which form/record object set a field belongs. It is not merely a matter of positioning them “at the top”, but understanding how where they are positioned affects the QBM and body created.
For example:
for Invoice ;
list records
CustomerID in groups ;
CustomerName ;
Amount .
creates two containers – one for the grouped items, and one for the items that belong to that group. A previously – and maybe even currently – undocumented ‘feature’ is that all the fields above the grouped field belong to the group container.
Here the customer name will repeat for every item in that group, which I presume is not what the user wants.
The proper DQL is:
for Invoice ;
list records
CustomerName ;
CustomerID in groups ;
Amount .
This will position CustomerName in the container it belongs – the grouped items – and not in the individual records for that group.
In DOS, people were used to writing the DQL and then re-arranging the fields in the format. In DfW, you must write the DQL to position the fields in their proper container in the body.
For the same reason, listing in order should be done in the appropriate container. Thus:
for Invoice ;
list records
CustomerName ;
InvoiceDate in order ;
CustomerID in groups ;
Amount .
Putting InvoiceDate above CustomerID will result in that field appearing in the grouped container, and only showing the value of the first record in the group – again, not what the user wants.
“Ad-hoc relationships based on virtuals…”
One key problem with virtual fields is that many people don’t understand how to use them properly. In addition, whereas the DOS environment meant that even absurd coding using virtuals was usually ignored, the Windows environment brings with it new memory issues that allow for multi-tasking and the like, and cannot be ignored.
As I pointed out a few Dialogues ago, I found a vertical 4.53 application that I migrated for testing purposes to DfW. I found that it migrated fine, except for one problem – a virtual field derived as “lookup ThisRel Value”, where the virtual itself was the match in the relationship! DOS forgave this; DfW (rightly) objected.
Whilst I would say that one source of GPFs is poor use of virtual fields, I would also say that, used properly, virtuals belong in the DataEase application (see, for example, Chris Gadsby’s excellent article on project methodology in the same issue, p18, col 1, “Entity Level Data Dictionary”, in which he singles out as part of the process the identification of virtual attributes).
Thus my concern is that people are put off using virtuals “because Sapphire said so”. You were correct that they “may cause recursive calculations” … but then again, they may not.
I also think that the ‘recursive problem’ is not limited to ad-hocs, but applies to all relationships.
“Reference to System forms are invalid in DfW…”
Since when? That should be ‘system tables’, of course, but I know of no reason not to use them, as long as DfW has a corresponding table. After all, the DQL scheduler is just a pseudonym for “for system configuration with computer name = blank…”.
Of course, you have to check “show system tables” in the application preferences dialog. And maybe some of the things people do with system tables are dubious. But the above statement is in and of itself incorrect.
“The output command .. in many cases … can be dropped.”
Whilst it is correct to point out its redundancy, I’d say that in every case it can be dropped, though please give an example of where it can be kept if I’m wrong. I’ve never used it in a DfW application, since we can use nested fors and multiple list records instead.
I’m slightly dubious about the line “if a … procedure has multiple non-nested for loops, break it up into separate procedures”. Such constructions are possible, as long as one understands how the QBM/multi-view is affected. But I agree that ‘rambling’ DQLs that don’t respect the QBM/multi-view are likely to be problematic, and am minded that you group these under “other general rules”, especially since such considerations were not applicable to DOS, and therefore even the best programmer could code stuff that won’t work in DfW. Your recommendation in the next paragraph to “keep procedures to a single outer for loop” is good advice.
The article also continues to refer to ‘forms’. The longer the DataEase developer/user confuses forms with tables, the longer it will take to appreciate the true power of separating form and table design.
I agree with all the other suggestions and comments made in the article.
Sorry to sound so harsh, but I’ve tried in these pages and on the various forums to develop a true understanding for the readers of how DfW works, and to overcome some of the many mis-assumptions about the product.
Your turn to disagree...
Thursday, 15 April 2010
Relatively Speaking, 2010
I’ve been thinking a lot about relationships recently, but writing a ‘Definitive Guide’ seems such an enormous task that I’ve decided to make this a parts work, and focus on one area per blog.
Here’s a rough guide to where I’m going, though.
Relationships are one of the jewels in the DE-Ff crown. The simple connection of one table to another by common values yields many possibilities. Yet these have been little explored in writing, and there are myths from the DOS days still floating around.
The Relationships form essentially consists of three (well, 3 ½) main areas: the two tables to be matched; the match fields; and the names.
(The half is referential integrity, which I’ll look at much later.)
You can link two different tables, or you can link the same table to itself.
The fields you specify either uniquely identify that table, or they don’t. If they do, that side by definition is the ‘one’ side. If not, it must be the ‘many’ side.
We’ll tackle the thorny issue of ‘fields that identify’ later.
There is one exception to the above – when there are NO match fields! I’ll definitely be exploring this more!
The name is an alias for how one side sees the other. You can think of it as being a property of that side, so that “Customer.SeeInvoices” (to borrow notation from object oriented programming) shows each customer has a collection of zero or more invoices.
My naming suggest the type of relationship, and I also try to make it as ‘English’ as possible. However, we are restricted by a maximum of twenty chars in DE 6.x, and since I have not yet confirmed that there are no issues with longer names in Ffenics, I still tend to stick to that limit. That can be tricky, of course, depending on the name and nature of the tables involved, so there may have to be a compromise for practical reasons.
By giving it a meaningful name, it should be quite clear what you can do with that relationship. ‘SeeInvoices’ means there may be a sub-form that displays all customer invoices. GetCustomer shows that the Invoice table can reference details in its one and only customer. Note that I use not only a prefix key word, but also the full name of the table (if the character count permits), and singular or plural.
One last comment: my preference is to put the ‘one’ side on the left and the ‘many’ on the right. This makes searching relationship records a lot easier!
Here’s a rough guide to where I’m going, though.
Relationships are one of the jewels in the DE-Ff crown. The simple connection of one table to another by common values yields many possibilities. Yet these have been little explored in writing, and there are myths from the DOS days still floating around.
Relational Groups
Think of relationships in two groups: structural and operational. Structural ones arise out of your entity relationship modelling. Operational ones, on the other hand, may appear to break modelling rules, but have many uses.The Relationships form essentially consists of three (well, 3 ½) main areas: the two tables to be matched; the match fields; and the names.
(The half is referential integrity, which I’ll look at much later.)
You can link two different tables, or you can link the same table to itself.
The fields you specify either uniquely identify that table, or they don’t. If they do, that side by definition is the ‘one’ side. If not, it must be the ‘many’ side.
We’ll tackle the thorny issue of ‘fields that identify’ later.
There is one exception to the above – when there are NO match fields! I’ll definitely be exploring this more!
Name Your Relationship!
Finally, there is the relationship name. There are many different types of relationships, and the name should reflect this.The name is an alias for how one side sees the other. You can think of it as being a property of that side, so that “Customer.SeeInvoices” (to borrow notation from object oriented programming) shows each customer has a collection of zero or more invoices.
My naming suggest the type of relationship, and I also try to make it as ‘English’ as possible. However, we are restricted by a maximum of twenty chars in DE 6.x, and since I have not yet confirmed that there are no issues with longer names in Ffenics, I still tend to stick to that limit. That can be tricky, of course, depending on the name and nature of the tables involved, so there may have to be a compromise for practical reasons.
By giving it a meaningful name, it should be quite clear what you can do with that relationship. ‘SeeInvoices’ means there may be a sub-form that displays all customer invoices. GetCustomer shows that the Invoice table can reference details in its one and only customer. Note that I use not only a prefix key word, but also the full name of the table (if the character count permits), and singular or plural.
One last comment: my preference is to put the ‘one’ side on the left and the ‘many’ on the right. This makes searching relationship records a lot easier!
Tuesday, 16 February 2010
Getting Round The Crash
I'm sure you know this one, don't you?
If, in any Windows version of DataEase or Ffenics, you are happily developing away and you get the dreaded "Exception" message to tell you that all the work you just didn't save is heading down to Rio, then:
Can 't guarantee it will always work, but as you only lifeline when this happens, always worth trying!
If, in any Windows version of DataEase or Ffenics, you are happily developing away and you get the dreaded "Exception" message to tell you that all the work you just didn't save is heading down to Rio, then:
- Curse
- Curse again
- Click the DataEase or Ffenics screen behind the message BEFORE you click ok, and
- Go File -- Save/Save As, etc
- Now click the GPF ok button to bomb out of your application.
Can 't guarantee it will always work, but as you only lifeline when this happens, always worth trying!
Labels:
Consultant,
Consulting,
DataEase,
Exception,
Ffenics,
GPF
Thursday, 11 February 2010
You live and Learn
Just found out something I didn't know re scripting.
If you are in the object about which you are scripting, you can omit the object name.
So, for example, if this is the ValueChanged event for FieldA, you DON'T need:
FieldA.Fill.Color.Red := 255 . etc
But can get away with:
Fill.Color.Red := 255 .
Show () .
Which saves some typing!
(I will also save some typing by NOT going back to old articles and blogs to adjust code. Sorry!)
More importantly, it means that a lot of scripts can be generic, as long as they reference the properties and methods of the current object, and that you are pasting them into objects that have those properties and methods.
If you are in the object about which you are scripting, you can omit the object name.
So, for example, if this is the ValueChanged event for FieldA, you DON'T need:
FieldA.Fill.Color.Red := 255 . etc
But can get away with:
Fill.Color.Red := 255 .
Show () .
Which saves some typing!
(I will also save some typing by NOT going back to old articles and blogs to adjust code. Sorry!)
More importantly, it means that a lot of scripts can be generic, as long as they reference the properties and methods of the current object, and that you are pasting them into objects that have those properties and methods.
Tuesday, 9 February 2010
Time at the Piano in New York
Just uploaded a new article to my website about my time in New York working on the World Trade Center disaster, and developing a new application for the Office of Chief Medical Examiner.
I think this is the third version I have written. The first appeared in Dialogue Magazine circa Winter 2001/2002, and I have no idea how to get hold of a copy.
The second was included in a volume of writings post 9/11 called 'On The Ground After 9/11' (ISBM: 789029073).
In this version, amongst other things, I compare DataEase and Ffenics to a piano, and the consultant to a pianist. A piano can't do everything. But compare the solo piano version of 'Rhapsody in Blue' to the full orchestral score, for example, and it is clear that on its own it does a pretty good version.
Similiarly, the piano is not every instrument, but is still a damn good solo instrument for beginner and virtuoso alike.
So it is with Ffenics. In the hands of a good solo performer, you can put together a pretty decent application to solve your small business needs.
Even in the hands of a rank amateur, does it not make a pleasing sound?
I think this is the third version I have written. The first appeared in Dialogue Magazine circa Winter 2001/2002, and I have no idea how to get hold of a copy.
The second was included in a volume of writings post 9/11 called 'On The Ground After 9/11' (ISBM: 789029073).
In this version, amongst other things, I compare DataEase and Ffenics to a piano, and the consultant to a pianist. A piano can't do everything. But compare the solo piano version of 'Rhapsody in Blue' to the full orchestral score, for example, and it is clear that on its own it does a pretty good version.
Similiarly, the piano is not every instrument, but is still a damn good solo instrument for beginner and virtuoso alike.
So it is with Ffenics. In the hands of a good solo performer, you can put together a pretty decent application to solve your small business needs.
Even in the hands of a rank amateur, does it not make a pleasing sound?
Labels:
9/11,
Consultant,
DataEase,
Ffenics,
New York,
Pianist,
Piano,
World Trade Center
Tuesday, 26 January 2010
The devil's in the DQL...
I'm probably going straight to hell, but ...
Our Ffenics,
Who art F7,
Relationships be named.
Thy index come,
F10 be done
In DOS as it is in Windows.
Give us this day our DQL
And forgive us our table views,
As we forgive those who table view against us.
Lead us not into temp form
But deliver us from Access.
For thine is the function,
The aspect and the query.
For ... ; enter a record
.end
Suggestions? Improvements? Absolution?
Our Ffenics,
Who art F7,
Relationships be named.
Thy index come,
F10 be done
In DOS as it is in Windows.
Give us this day our DQL
And forgive us our table views,
As we forgive those who table view against us.
Lead us not into temp form
But deliver us from Access.
For thine is the function,
The aspect and the query.
For ... ; enter a record
.end
Suggestions? Improvements? Absolution?
Labels:
Aspects,
DataEase for Windows,
DQL,
Ffenics,
Query,
Relationships,
Table View,
Temp Form
Wednesday, 20 January 2010
Letters, Loopers and Some Very Strange Relationships
Time for some daft, ‘out there’ ideas … and a bit of fun.
Here’s the goal: let’s imagine an environment, such as a busy, messy factory floor, where gloves and mess make it impossible to use a keyboard.
So you have a touch-sensitive screen, covered with a suitable protective layer, and want to give users the ability to look up something by typing in a reference number or keyword.
You need an on-screen keyboard, and because you love doing things in Ffenics or DataEase, you’re determined to create that keyboard using your favourite software.
Something like this:
So, we have a label, and field into which a value can be typed. There’s a funny arrow button to the right which is masquerading as a backspace button, a rough QWERTY keyboard plus integers, a blue bar representing the space bar, and a button labelled ‘Go’ which could be used to start a report that returns whatever it is supposed to return.
I’m using a couple of tricks here, including one that I’m surprised I’ve only just started to use regularly.
If you’re looked at other articles by me in which some set of buttons with letters from the alphabet is used, you should know that I have not wasted time and tightened every muscle in my back by laying out 36 buttons, each with their own set of scripts, to represent the keyboard. You should guess that I’m using a subform (just for the QWERTY letters and numbers; everything else is on the main form). And that the subform is build on my swiss-army-knife-of-a-dataset, Looper.
Or maybe you haven’t a clue what I’m on about. So let me explain.
Looper is a table of integers. To be precise, it is a table of ordinal numbers -- that is, integers in order. Why I call it Looper is my own business.
The area on screen is a 10 x 4 subform. Each record in that subform is a number from 1 to 40, the first 40 records in Looper.
The object with the appropriate letter displayed is a ‘layout-only virtual’, that is, a field that only exists on this document. It happens to be called vLetter, is one character long, and is derived:
midc ( "1234567890QWERTYUIOPASDFGHJKL ZXCVBNM " , LoopNo , 1 )
That odd string is the set of characters from your QWERTY keyboard, starting with the numbers across the top, then each row of upper case letters. The spaces towards the end help with the indenting of the keyboard.
LoopNo is our actual field in the form, the one containing the ordinal integer. The derivation basically finds the corresponding letter for the key. For example, the letter ‘R’ is in the second row and is four columns over on the keyboard; the ordinal number behind that record will therefore be 14, and the 14th letter in my string is the letter ‘R’.
As I said, these are records in a subform. But what’s the nature of the relationship? Well, this is one of my new tricks: the main form and Looper match based on … NO match fields.
Yes, they match on nothing. Nada. Zilch. And as a result, ALL records in the subform display. Try it and see with any old forms.
Now, Looper probably contains several thousand integers. But because I have removed the scrollbar from the subform, we only see the first 40 records. (Actually, if I had used a button instead of a text object for the letters, we’d have to deal with a minor issue about scrolling because the button can get focus, but let’s worry about that some other time.)
The letter field has two scripts: a clicked event for adding to the string of text in the main form’s ‘code’ field, and a ValueLoaded event to hide the field if its value is a space (to make the layout look a bit more like a keyboard).
The clicked event script is:
define "t" number .
Customer.FirstName.Value := concat ( Customer.FirstName.Value ,
if ( getarray ( 1 ) = "SpacePending" , " " , "" ) , vLetter.Value ) .
t := setarray ( 1 , "" ) .
Customer.FirstName.Show () .
In a recent blog post I covered how to update values between sub and main forms using scripts. Basically, we are adding the value of the letter to the end of the value already in our main form field.
Spaced Out
The getarray bit obviously needs explaining. It turns out that when you concat a space to the end of a field, the value in the field seems to immediately be trimmed of the trailing space.
The dark blue bar, as I mentioned above, is the space key. When this is clicked, this script:
define "t" number .
t := setarray ( 1 , "SpacePending" ) .
justs sets a flag, using array #1, to indicate that we are expecting a space. When a letter is clicked, we can then first insert such a pending space before the letter, and get around the trimming of spaces described.
Each letter also resets array #1 to blank, effectively meaning that the space is no longer pending.
The valueloaded script on the letter field is:
if vLetter.Value = " " then
vLetter.Hide () .
else
vLetter.Show () .
end
Two other things need mentioning. The first is that I found issues with Ffenics if the record contained no actual fields from the form. So Looper’s LoopNo is actually on the record, scrunched up in the top left corner. It has its new display option ‘hide’ checked, which means that it is never actually made visible. DataEase for Windows scripts didn’t need underlying fields present.
The other item is the backspace button. This deletes one character at a time from the string. Its script is:
Customer.FirstName.Value := firstc ( Customer.FirstName.Value ,
length ( Customer.FirstName.Value ) - 1 ) .
Customer.FirstName.Show () .
Of course, you might want to have more characters than I’ve chosen. I’m sure someone could have some fun working out how to put the display into upper or lower case, or to imitate the keyboards found on some PDAs and smart phones. You could also add a ‘Clear All’ button. And another intriguing problem would be to have more than one field for data-entry. That’s your homework.
Time to implement this from scratch: less than one hour. Click title for PDF version from my website.
Here’s the goal: let’s imagine an environment, such as a busy, messy factory floor, where gloves and mess make it impossible to use a keyboard.
So you have a touch-sensitive screen, covered with a suitable protective layer, and want to give users the ability to look up something by typing in a reference number or keyword.
You need an on-screen keyboard, and because you love doing things in Ffenics or DataEase, you’re determined to create that keyboard using your favourite software.
Something like this:
So, we have a label, and field into which a value can be typed. There’s a funny arrow button to the right which is masquerading as a backspace button, a rough QWERTY keyboard plus integers, a blue bar representing the space bar, and a button labelled ‘Go’ which could be used to start a report that returns whatever it is supposed to return.
I’m using a couple of tricks here, including one that I’m surprised I’ve only just started to use regularly.
If you’re looked at other articles by me in which some set of buttons with letters from the alphabet is used, you should know that I have not wasted time and tightened every muscle in my back by laying out 36 buttons, each with their own set of scripts, to represent the keyboard. You should guess that I’m using a subform (just for the QWERTY letters and numbers; everything else is on the main form). And that the subform is build on my swiss-army-knife-of-a-dataset, Looper.
Or maybe you haven’t a clue what I’m on about. So let me explain.
Looper is a table of integers. To be precise, it is a table of ordinal numbers -- that is, integers in order. Why I call it Looper is my own business.
The area on screen is a 10 x 4 subform. Each record in that subform is a number from 1 to 40, the first 40 records in Looper.
The object with the appropriate letter displayed is a ‘layout-only virtual’, that is, a field that only exists on this document. It happens to be called vLetter, is one character long, and is derived:
midc ( "1234567890QWERTYUIOPASDFGHJKL ZXCVBNM " , LoopNo , 1 )
That odd string is the set of characters from your QWERTY keyboard, starting with the numbers across the top, then each row of upper case letters. The spaces towards the end help with the indenting of the keyboard.
LoopNo is our actual field in the form, the one containing the ordinal integer. The derivation basically finds the corresponding letter for the key. For example, the letter ‘R’ is in the second row and is four columns over on the keyboard; the ordinal number behind that record will therefore be 14, and the 14th letter in my string is the letter ‘R’.
As I said, these are records in a subform. But what’s the nature of the relationship? Well, this is one of my new tricks: the main form and Looper match based on … NO match fields.
Yes, they match on nothing. Nada. Zilch. And as a result, ALL records in the subform display. Try it and see with any old forms.
Now, Looper probably contains several thousand integers. But because I have removed the scrollbar from the subform, we only see the first 40 records. (Actually, if I had used a button instead of a text object for the letters, we’d have to deal with a minor issue about scrolling because the button can get focus, but let’s worry about that some other time.)
The letter field has two scripts: a clicked event for adding to the string of text in the main form’s ‘code’ field, and a ValueLoaded event to hide the field if its value is a space (to make the layout look a bit more like a keyboard).
The clicked event script is:
define "t" number .
Customer.FirstName.Value := concat ( Customer.FirstName.Value ,
if ( getarray ( 1 ) = "SpacePending" , " " , "" ) , vLetter.Value ) .
t := setarray ( 1 , "" ) .
Customer.FirstName.Show () .
In a recent blog post I covered how to update values between sub and main forms using scripts. Basically, we are adding the value of the letter to the end of the value already in our main form field.
Spaced Out
The getarray bit obviously needs explaining. It turns out that when you concat a space to the end of a field, the value in the field seems to immediately be trimmed of the trailing space.
The dark blue bar, as I mentioned above, is the space key. When this is clicked, this script:
define "t" number .
t := setarray ( 1 , "SpacePending" ) .
justs sets a flag, using array #1, to indicate that we are expecting a space. When a letter is clicked, we can then first insert such a pending space before the letter, and get around the trimming of spaces described.
Each letter also resets array #1 to blank, effectively meaning that the space is no longer pending.
The valueloaded script on the letter field is:
if vLetter.Value = " " then
vLetter.Hide () .
else
vLetter.Show () .
end
Two other things need mentioning. The first is that I found issues with Ffenics if the record contained no actual fields from the form. So Looper’s LoopNo is actually on the record, scrunched up in the top left corner. It has its new display option ‘hide’ checked, which means that it is never actually made visible. DataEase for Windows scripts didn’t need underlying fields present.
The other item is the backspace button. This deletes one character at a time from the string. Its script is:
Customer.FirstName.Value := firstc ( Customer.FirstName.Value ,
length ( Customer.FirstName.Value ) - 1 ) .
Customer.FirstName.Show () .
Of course, you might want to have more characters than I’ve chosen. I’m sure someone could have some fun working out how to put the display into upper or lower case, or to imitate the keyboards found on some PDAs and smart phones. You could also add a ‘Clear All’ button. And another intriguing problem would be to have more than one field for data-entry. That’s your homework.
Time to implement this from scratch: less than one hour. Click title for PDF version from my website.
Labels:
DataEase for Windows,
Ffenics,
Looper,
Scripting
Wednesday, 13 January 2010
Tuesday, 12 January 2010
... And Looking Down
Following from my last post we should consider how you use script to point from an object in a main form to a specific row in a subform.
Here, life is not so rosy. Yes, this script will copy main form value to subform:
MySubform.MySubformField.Value := MainFormField.value .
MySubform.MySubformField.show () .
The trouble is, this will only update the first visible subform row. Now, if you're only displaying one subform record, that might not be an issue. But otherwise, whatever is the top row currently visible is the one that is targeted. Not the first in the dataset, note: the first visible. Scroll the list so that the top one pops off and you'll now be affecting the value in the row that was previously below.
Now, I'm not entirely sure why one would want to do such a thing in the first place, but no doubt someone will want to do something like this. I therefore post for completeness.
If the goal was to change the value in all sub records, you could do this using a procedure instead, followed by use of the RefreshScreen action (all existing records will magically be updated). You could also include the field you want to copy to the subform records in a relationship, and use that relationship for the subform.
Thoughts, anyone?
Here, life is not so rosy. Yes, this script will copy main form value to subform:
MySubform.MySubformField.Value := MainFormField.value .
MySubform.MySubformField.show () .
The trouble is, this will only update the first visible subform row. Now, if you're only displaying one subform record, that might not be an issue. But otherwise, whatever is the top row currently visible is the one that is targeted. Not the first in the dataset, note: the first visible. Scroll the list so that the top one pops off and you'll now be affecting the value in the row that was previously below.
Now, I'm not entirely sure why one would want to do such a thing in the first place, but no doubt someone will want to do something like this. I therefore post for completeness.
If the goal was to change the value in all sub records, you could do this using a procedure instead, followed by use of the RefreshScreen action (all existing records will magically be updated). You could also include the field you want to copy to the subform records in a relationship, and use that relationship for the subform.
Thoughts, anyone?
Labels:
DataEase for Windows,
Ffenics,
OCL,
OML,
Scripting
Looking Up
Here's a quick Ffenics scripting snippet, on my mind since it just came up in a bit of support. Should also apply to DataEase for Windows 6.52 and 7.x.
You have a sub-form, and you want to copy a value to your main form:
MainForm.MyTargetField.Value := MySourceField.Value .
MainForm.MyTargetField.Show () .
This script could be placed in a button's clicked event, or in the clicked event of a virtual field. Just make sure in either case that this is an object on your subform.
Note the 'dot notation' to navigate from the outermost object inwards to locate the target field. MainForm is the name of the form object that wraps the entire document. This will be the same as the name of the actual form/table on which the document is based, whose name you cannot change. Just bear in mind we are talking about the object on screen, and not the form/table defining and containing your data.
MyTargetField is a field object on MainForm. Again, the name is likely to be the same as a field in your form/table, but, again, we are talking about the textbox object on screen, and we are setting its value property.
The ':=' assignment is sufficient to perform the data change (if you only had this line of code, clicked the button in user view and then attempted to close the document, you'd get a 'save data changes' message). However, it does not cause the screen to be repainted, and therefore without the '.show()' method, it would appear as though nothing has happened.
The source value resides in a field object MySourceField in your subform, and on that same subform will be the button with this code. For that reason, you don't need any dot navigation to get to the appropriate field, and this code will update the main form value with whichever is the appropriate value in the subform.
As with many scripting examples, it seems to take a lot of words to describe what is going on. The constant key confusion with scripting, I find, is that people mix up the concepts of the data with the objects on the form. Hence why you have to refer to the value property of the field object, and not simply the field name itself as you might in a field derivation or DQL.
Doing the scripting the other way -- from main to subform -- is, however, problematic. I'll look at that in a later post.
You have a sub-form, and you want to copy a value to your main form:
MainForm.MyTargetField.Value := MySourceField.Value .
MainForm.MyTargetField.Show () .
This script could be placed in a button's clicked event, or in the clicked event of a virtual field. Just make sure in either case that this is an object on your subform.
Note the 'dot notation' to navigate from the outermost object inwards to locate the target field. MainForm is the name of the form object that wraps the entire document. This will be the same as the name of the actual form/table on which the document is based, whose name you cannot change. Just bear in mind we are talking about the object on screen, and not the form/table defining and containing your data.
MyTargetField is a field object on MainForm. Again, the name is likely to be the same as a field in your form/table, but, again, we are talking about the textbox object on screen, and we are setting its value property.
The ':=' assignment is sufficient to perform the data change (if you only had this line of code, clicked the button in user view and then attempted to close the document, you'd get a 'save data changes' message). However, it does not cause the screen to be repainted, and therefore without the '.show()' method, it would appear as though nothing has happened.
The source value resides in a field object MySourceField in your subform, and on that same subform will be the button with this code. For that reason, you don't need any dot navigation to get to the appropriate field, and this code will update the main form value with whichever is the appropriate value in the subform.
As with many scripting examples, it seems to take a lot of words to describe what is going on. The constant key confusion with scripting, I find, is that people mix up the concepts of the data with the objects on the form. Hence why you have to refer to the value property of the field object, and not simply the field name itself as you might in a field derivation or DQL.
Doing the scripting the other way -- from main to subform -- is, however, problematic. I'll look at that in a later post.
Tuesday, 5 January 2010
The Model Is King, Pt 1
In DataEase and Ffenics, the data model -- that thing that is represented by a little diagram in the query by model dialog -- is king. Whenever a change in a procedure, say, sends your procedure body to the waste disposal, you can bet you made a change that affected the data model.
I was reminded of this in a support call this week, where the user had a pride-and-joy procedure with a beatiful, bouncing layout ... and they wanted to make what seemed like a simple change. They added a line of code before the main 'for' loop that checked to see that a value in the data-entry form was set:
if data-entry MyValueToCheck = blank then exit . end .
Why would such a simple addition bring the roof down? Because it changes the data model.
Basically -- and this is another golden rule -- for every document, there can only be one parenting table. Perhaps less obvious is that this 'if' command required something to parent it ... and in these instances Ffenics and DataEase inserts its standby DQL Scheduler. Try it and see:
In the meantime, there are several workarounds (other than start again...):
I was reminded of this in a support call this week, where the user had a pride-and-joy procedure with a beatiful, bouncing layout ... and they wanted to make what seemed like a simple change. They added a line of code before the main 'for' loop that checked to see that a value in the data-entry form was set:
if data-entry MyValueToCheck = blank then exit . end .
Why would such a simple addition bring the roof down? Because it changes the data model.
Basically -- and this is another golden rule -- for every document, there can only be one parenting table. Perhaps less obvious is that this 'if' command required something to parent it ... and in these instances Ffenics and DataEase inserts its standby DQL Scheduler. Try it and see:
- Mock up a simple for/list records
- Accept the default body
- Move one of the fields just to highlight that it is changed
- Add an if command above the for (try 'if year ( current extended date ) = 2010 then exit . end .')
- Compile and accept the default 'merge changes' for the new layout.
- Note than previously moved field is back to its default position.
- Go to Document -- View Data model to see that the DQL Scheduler table has been inserted at the left.
In the meantime, there are several workarounds (other than start again...):
- Add the sense of the 'if' to the selection criteria for the main 'for' ('for MyTable with data-entry MyField not = blank' )
- Add the 'if ... exit ... end' statement as is immediately after the 'for MyTable'
- Add some logic (e.g. make the field required) to the data-entry form/interactive header to do the check for you in the first place.
Thursday, 10 December 2009
Obscure Bug or Dumb Developer? Mmmm, Probably the Latter
Let me hope I'm not blogging too early, but I may have just solved something that has been driving me nuts!
I could not work out why Google refused to find my website, save for the PDF files.
I had everything in place I should, I thought -- robot.txt, sitemap, etc, etc. The site views fine with every browser I have on my PC.
But check it out with google webmaster and it says, on every page, "network unreachable".
And now I think I know why.
Like every good website, I'm tracking visitors, and since this was my first bit of development in ASP.NET, I added my own visit-recording routine. It picks off from the visitor's broswer a number of variables, including the UserLanguages collection. These are the default languages that you like to browse in, and was giving me a rough and ready guide to country of origin.
Except the googlebot browser is different. Either it or the object that .NET uses to represent it lacks this collection ... and in .NET, if you try to access something that isn't there, you get an error instead of your page.
Of course, I should have asked the question on the google forum ages ago, but you know, there are just some things you don't get around to! Well, I did today, and a kind respondent pointed me in the direction of a site (http://www.rexswain.com/httpview.html) that shows precisely what was going on from a web-botty perspective.
Dumb developer, I think, is really to blame. Hopefully, problem fixed. Fingers x-ed as I wait for google to moozy over to n10net for a new look. What a patient botty to keep putting up with my incompetence!
I could not work out why Google refused to find my website, save for the PDF files.
I had everything in place I should, I thought -- robot.txt, sitemap, etc, etc. The site views fine with every browser I have on my PC.
But check it out with google webmaster and it says, on every page, "network unreachable".
And now I think I know why.
Like every good website, I'm tracking visitors, and since this was my first bit of development in ASP.NET, I added my own visit-recording routine. It picks off from the visitor's broswer a number of variables, including the UserLanguages collection. These are the default languages that you like to browse in, and was giving me a rough and ready guide to country of origin.
Except the googlebot browser is different. Either it or the object that .NET uses to represent it lacks this collection ... and in .NET, if you try to access something that isn't there, you get an error instead of your page.
Of course, I should have asked the question on the google forum ages ago, but you know, there are just some things you don't get around to! Well, I did today, and a kind respondent pointed me in the direction of a site (http://www.rexswain.com/httpview.html) that shows precisely what was going on from a web-botty perspective.
Dumb developer, I think, is really to blame. Hopefully, problem fixed. Fingers x-ed as I wait for google to moozy over to n10net for a new look. What a patient botty to keep putting up with my incompetence!
Thursday, 3 December 2009
Doctor's Handwriting
Today's Radio 4 Today programme has a story where "Nearly one in 10 hospital prescriptions contain a mistake, ranging from the minor to the potentially lethal." (http://news.bbc.co.uk/1/hi/health/8391667.stm)
Reasons given include the inevitable issues of handwriting, but also prescribing drugs without regard to the patient's allergies, and getting the dosage wrong.
Why, I have to ask, are prescriptions being hand-written at all? Why not crossed referenced with a list of allergies to at least alert the doctor to possible conflicts? Checked to ensure no obvious mistakes in dosage?
Why not generated from a computer system to do all the above, and more?
Is there an opportunity for Ffenics here, for a PrescriptionEase, for a simple-to-generate and low-cost app?
Reasons given include the inevitable issues of handwriting, but also prescribing drugs without regard to the patient's allergies, and getting the dosage wrong.
Why, I have to ask, are prescriptions being hand-written at all? Why not crossed referenced with a list of allergies to at least alert the doctor to possible conflicts? Checked to ensure no obvious mistakes in dosage?
Why not generated from a computer system to do all the above, and more?
Is there an opportunity for Ffenics here, for a PrescriptionEase, for a simple-to-generate and low-cost app?
Wednesday, 2 December 2009
Out of Sight, Not Out Of Mind: Thoughts on Ffenics Object Scripting
If you want to pass, say, the ID for a record to the setglobal function using Ffenics or DataEase scripting, you need to include some field object on screen.
So a typical scenario might be to create a virtual in your Ffenics form derived from the ID value (or to add a 'layout only field' to an aspect), place this field on the screen, and refer to its 'value' property in the script.
You don't necessarily want the actual data to appear to the user, so somehow you have to style it so that it is not visible, and scrunch it up in a corner somewhere to keep it out of range of the things you actually want the user to see. If it overlaps with visible objects, it may partially obscure them. And because you have set it to look like it is not there, it's hard to spot it when in designer view.
The new 'Hide' option on the Ffenics display dialog for an object does away with this, and can both simplifiy and help with development. By placing a field on screen and then checking this property, you can still reference the value it contains, but the object, as you'd imagine, simply does not appear. In addition, it can overlap with other visible objects without causing runtime oddities in appearance.
And you can give such objects a 'hidden field' style that, in designer view, makes them totally obvious (give them a nice bright red background, why don't you) so you can spot them when you're building your wonderful aspect, safe in the knowledge that they will be forever invisible to the user.
So a typical scenario might be to create a virtual in your Ffenics form derived from the ID value (or to add a 'layout only field' to an aspect), place this field on the screen, and refer to its 'value' property in the script.
You don't necessarily want the actual data to appear to the user, so somehow you have to style it so that it is not visible, and scrunch it up in a corner somewhere to keep it out of range of the things you actually want the user to see. If it overlaps with visible objects, it may partially obscure them. And because you have set it to look like it is not there, it's hard to spot it when in designer view.
And you can give such objects a 'hidden field' style that, in designer view, makes them totally obvious (give them a nice bright red background, why don't you) so you can spot them when you're building your wonderful aspect, safe in the knowledge that they will be forever invisible to the user.
Friday, 27 November 2009
That Was The Workshop That Was
At the start of this week I ran my second DataEase/Ffenics training workshop.
The first one was eight years ago, and I do kick myself for not having thought to run more since. Still, I've started again, and will absolutely maybe do it again in the new year.
Last time I ran the event in conjunction with Richard Laidler, who's now retired from the DE world. So it was (mostly) all my own work. I'm not the greatest of organisers, but it wasn't that complicated to arrange. Choosing my birth town of Bristol eliminated a few practical issues, and a bit of time putting together a website, and promoting it largely through the Ffenics forum gained enough interest to make it worthwhile.
The great thing about workshops and conference gatherings and the like is you get to spend a day or two, immersing yourself in the subject. I imagine for most of us, our development time is a solitary one, with little opportunity to explore with a single colleague, let alone several people, the things we are trying to solve, and find the other person enthused in the process.
The benefit is not simply that you learn new techniques and solve or confirm old problems. I think we are addressing one of those higher levels in Maslow's hierarchy of needs -- esteem. No doubt we all may from time to time feel buffeted by the gales of change that forever blow through the world of IT, and wonder whether our trusty boat The Good Ship Ffenics is up to the job of navigating these windy seas. I'd like to think that our two days this week gave a good confidence boost to attendees, not just because of my incredible words of wisdom and demo apps, but to engage with the others there, and see their apps rocking in action. Hey, even my brother, whose a C++/PhP type of developer, was impressed with Ffenics!
Anyway, enough of this for the moment. I hope to get to grips with extracting some usable video footage from the small pile of DVDs in front of me, if I can ever get over the embarrassment of watching myself gesticulating like a windmill on acid!
Thanks to Graham Smith at PLM Consulting in the USA, who gave a Webex/Skype presentation to the group on styling and code reuse, and to delegate John Baldwin, who agreed to kick off a debate about some of the difficulties he's had in moving from DOS to Ffenics. To the other delegates for making the journey over to Bristol ... and to my brother Neill, who videoed and gopher’ed for me.
The first one was eight years ago, and I do kick myself for not having thought to run more since. Still, I've started again, and will absolutely maybe do it again in the new year.
Last time I ran the event in conjunction with Richard Laidler, who's now retired from the DE world. So it was (mostly) all my own work. I'm not the greatest of organisers, but it wasn't that complicated to arrange. Choosing my birth town of Bristol eliminated a few practical issues, and a bit of time putting together a website, and promoting it largely through the Ffenics forum gained enough interest to make it worthwhile.
The great thing about workshops and conference gatherings and the like is you get to spend a day or two, immersing yourself in the subject. I imagine for most of us, our development time is a solitary one, with little opportunity to explore with a single colleague, let alone several people, the things we are trying to solve, and find the other person enthused in the process.
The benefit is not simply that you learn new techniques and solve or confirm old problems. I think we are addressing one of those higher levels in Maslow's hierarchy of needs -- esteem. No doubt we all may from time to time feel buffeted by the gales of change that forever blow through the world of IT, and wonder whether our trusty boat The Good Ship Ffenics is up to the job of navigating these windy seas. I'd like to think that our two days this week gave a good confidence boost to attendees, not just because of my incredible words of wisdom and demo apps, but to engage with the others there, and see their apps rocking in action. Hey, even my brother, whose a C++/PhP type of developer, was impressed with Ffenics!
Anyway, enough of this for the moment. I hope to get to grips with extracting some usable video footage from the small pile of DVDs in front of me, if I can ever get over the embarrassment of watching myself gesticulating like a windmill on acid!
Thanks to Graham Smith at PLM Consulting in the USA, who gave a Webex/Skype presentation to the group on styling and code reuse, and to delegate John Baldwin, who agreed to kick off a debate about some of the difficulties he's had in moving from DOS to Ffenics. To the other delegates for making the journey over to Bristol ... and to my brother Neill, who videoed and gopher’ed for me.
Friday, 13 November 2009
Naming Conventions
Ffenics consultants will nag on about not using reserved words, adopting single word naming conventions and so on, but the truth is that DataEase and Ffenics are so resillient to these mistakes that 95% of the time you can probably get away with them.
We'll still laugh at you, of course, unless it's your round.
But I did just come across an instance where idiosyncratic nomenclature aims its teeth at your derriere: punctuation such as brackets (or parenthesis) confuse attempts to write object scripts.
Every book on computing you'll ever read will tell you to stick to single word names, but if you managed to skip those pages, or are looking after an app created by AN Other, then there is a workaround: use the 'object name' option on the field definition dialog, and change the object name at least to a single word.
Ff uses the field name from the form/table to be the default name for the object on a form or aspect that displays the data. It also uses the same name for summary field objects. You cannot have objects with the same name in the same container, but the corresponding summary object for a regular field object will be created in the form container, not in the record container, so there is no immediate confusion. Still, not a bad idea, if you are likely to do a lot of scripting on a document that has summary variables, to rename them to something easier to spot in the script object list.
We'll still laugh at you, of course, unless it's your round.
But I did just come across an instance where idiosyncratic nomenclature aims its teeth at your derriere: punctuation such as brackets (or parenthesis) confuse attempts to write object scripts.
Every book on computing you'll ever read will tell you to stick to single word names, but if you managed to skip those pages, or are looking after an app created by AN Other, then there is a workaround: use the 'object name' option on the field definition dialog, and change the object name at least to a single word.
Subscribe to:
Posts (Atom)