by Dr. Peter Wayne
| This article and the accompanying tables and forms illustrate a bullet-proof approach to memo fields. |
Call me obsessive, but I cannot bear the thought of ever losing one of my memos. In my medical practice, we store tens of thousands of medical notes (at last count, over 60,000) in memo fields. These memo fields are created and accessed on a Windows 98 peer-to-peer network, using Alpha Five 4.03. The computer that serves as the repository of all the files is also used for data entry, which I have been repeatedly told is a no-no. Some people would think that we have to rebuild indexes and memo files daily. In point of fact, I haven't rebuilt the index for the memo file in over a year.
There are a few secrets to maintaining reliable memo fields:
1) All new memo fields are created using Xbasic. They are then edited by the
user in a form that does not allow navigation off the record.
2) All navigation through tables is done when the tables are in read-only mode.
When editing is allowed, navigation is turned off.
3) Deletion is not allowed in our application, but if deletion is required, it
also should be done through Xbasic.
For illustrative purposes, I have created a project tracking mini-application with 2 tables: projects.dbf and prjct_prg.dbf. The structure of the tables is as follows:
| Project_ID | Character | 3 | 0 |
| Project_Name | Character | 30 | 0 |
| Start_Year | Numeric | 4 | 0 |
| End_Year | Numeric | 4 | 0 |
Table 1. Structure of Projects.dbf.
| Project_ID | Character | 3 | 0 |
| Date_of_Entry | Date | 8 | 0 |
| Progress | Memo | 10 | 0 |
| Editing | Logical | 1 | 0 |
Table 2. Structure of Prjct_Prg.dbf
The mini-application starts with a form, ProjectIndex2, that has a tabbed subform on it. The first page of the tabbed subform lets the user select a project. The second page, labeled "Detail", allows the user to edit the project:

Fig. 1. The first tabbed page of the ProjectIndex2 form.
The second page of the form shows the detail for the project:

Fig. 2. The Detail page of the ProjectIndex2 form.
There are scripts all over this form. The form's OnInit script turns off editing for the form and the browse:
this:browse1.browse.readonly=.t. this.restrict_enter=.t. this.restrict_change=.t. this.restrict_delete=.t.
Script 1. OnInit script for ProjectIndex2 form.
Pressing the "Allow Change" button puts the form into editing mode and moves focus to the second tab page:
this.disable() if this.text="Allow Change" then parent.restrict_change=.f. parent.restrict_delete=.f. parent.restrict_navigation=.t. parent.restrict_query=.t. parent.restrict_locate=.t. parent.restrict_range=.t. tabbed1.tab_set(2) this.text="Prevent Change" else parent.restrict_change=.t. parent.restrict_delete=.t. parent.restrict_navigation=.f. parent.restrict_query=.f. parent.restrict_locate=.f. parent.restrict_range=.f. tabbed1.tab_set(1) this.text="Allow Change" end if this.enable()
Script 2. OnPush script for Button1, the button that allows editing of an existing project.
Pressing the button a second time puts the form back into read-only mode and moves the tab back to the first page. Pressing one of the tab buttons does the same thing, as long as any changes have first been saved or discarded:
if parent.mode_get()<>"VIEW" then
cancel()
ui_msg_box("You are in change or entry mode","Save or discard your changes first")
end if
Script 3. The CanChangeTab script for the Tabbed1 object keeps the user from moving off the second page of the tab before committing or discarding edits.
if this.tab_get()=1 then button1.text="Allow Change" parent.restrict_change=.t. parent.restrict_delete=.t. parent.restrict_navigation=.f. parent.restrict_query=.f. parent.restrict_locate=.f. parent.restrict_range=.f. end if
Script 4. The OnTabChange script for Tabbed1 puts the form back in read-only mode.
this.disable() browse1.browse.readonly=.f. parent.restrict_enter=.f. parent.restrict_change=.f. browse1.new_record() browse1:project_name.text="Enter project name here" browse1:project_name.value="Enter project name here" browse1.commit() browse1.browse.readonly=.t. parent.restrict_enter=.t. tabbed1.tab_set(2) project_name.activate() button1.text="Prevent Changes" this.enable()
Script 6. The "New Projects" button script adds a new project and then moves focus to the second tab page and allows the newly entered project to be edited.
this.disable()
f=form.load("view project")
f.restrict_change=.f.
f:Tables:prjct_prg.filter_expression="project_id='"+browse1:project_id.text+"'"
f:Tables:prjct_prg.order_expression="invert(date_of_entry)"
f:Tables:prjct_prg.query()
f:id.text=browse1:project_id.text
f:name.text=browse1:project_name.text
f.restrict_change=.t.
f.resynch()
ix=f:Tables:prjct_prg.index_primary_get()
nrecs=ix.records_get()
if nrecs=0 then
f:browse1.hide()
end if
f.show()
f.activate()
this.enable()
parent.hide()
Script 7. This "View Progress" button script opens a form that lists all the progress notes for an individual project. Notice that the main form hides itself when the "View Project" form is run. Here is the "View Project" form:
Fig.3. This form also has a series of button scripts and a script attached to the OnRowDblClick event of the browse. This browse is also in read-only mode, and the only way to edit a memo is through a third form, shown below:
Fig.
4. This is the only form that actually allows editing of the memo.
I won't go over all the different scripts in these 3 forms--that's why there's
a download for you to look at and study. They should afford you a solid
afternoon's work. Enjoy!
Download the tables and forms used in this article.
4/21/02 - pkw
Don't forget, we need your feedback to make this site better!