![]() |
|
| Below are notes and tips arising from discussions
at past meetings. many of the v5.5 tips are now quite old but
it seemed wrong to assume that no one now used v5.5. |
|
New!v7.01Passing Properties Between Forms |
We thought we knew how to do this but it took us half an hour to get it right! So, in case you too are unsure...... Assume a Parent and a Child form. From the Parent we want to instantiate the Child, setup variables in the Child form and assign values to them. Then open the Child form in such a way that the Child has access to the values. In the Parent we define a button with an OnClick event called PUSHBUTTON1_OnClick. function PUSHBUTTON1_onClick set proc to child.wfm additive oChild.readmodal() In the Child, any passed properties need to be triggered before the form is opened. So start the Class .... lines with the default readmodal() method set to your own "form_open" function. This must always end by calling default (or "Super") readmodal() method. class childForm of FORM The Form_Open function comprises: function form_open The Inspect(this) line, commented out above, is useful for checking which properties and values have actually been passed. The next line puts the passed value into an entryfield. This is not necessary for the text object as the Parent form had set a specific value for this rather than pass a value through a variable, as with the Entryfield. this.TITLE = new TEXT(this) When tested this did in fact show the passed "Success!" and not the single space as above A pushbutton on the child form calls: function PUSHBUTTON1_onClick If the figure in the entryfield is changed before clicking the button, the Message Box that pops up in the Parent form will show the new value. And so proves that values can be passed both ways between forms. A point to watch. A modal form is used above as execution in the Parent form halts until the Child form is closed. The revised entryfield value is then known to the Parent form and shown. If the Child form is not opened modally, execution does not halt and the Message box will show the value passed to the child, not the value returned. Worth remembering, it can often lead to initially inexplicable errors! Also, remember to put: readmodal = Class::Form_Open. If this line starts with open (as it will if the Designer is used), the line will be ignored if the form is called with a readmodal().
See also below for a further example of he use of passed properties |
|
New!v7.01Defining Objects with Macros. |
This does not appear to be possible using the Object.... = new ....... construct favoured by v7.01 However the Define method normally used in v5.5 can still be used and does allow object names to be formed in a loop with macros. Although the method shown below does work, any suggestions for doing it a better way will be very welcome! A Selector.wfm form is used to popup with a variable number of buttons where a user choice is required. Below is an example of code used to call the form and handle the returned value: function PBUTSelect_onClick Local cSequence,sSeq // popup form with buttons for various tasks Set Procedure to Selector.wfm additive sSeq.PbNumb = 6 // set number of buttons sSeq.Readmodal() // open form modally cSequence = sSeq.Select // receive returned value Do Case Case cSequence = 'B' // do whatever The called Selector form has a "readmodal = Class::Form_Open" line (see tip above) which calls: function form_open height = 3 + (form.PbNumb*1.5) // calc form height from no
of buttons specified cTitle = form.PbTitle // form title For nCtr = 1 to form.pbnumb // loop for each required button cSctr = lTrim(Str(nCtr,1)) // make the loop counter into a
string next SELECTORFORM::readmodal() // now open the form, modally, as normal return The pushbutton OnClick events defined above (six in this example) each put a relevant value in the form.select property that is used by the calling form to identify the choice made by the user. NB, do not open a form with objects defined in a loop in the Designer, it is liable to do unwanted things with it! NOTE. The full code for Selector.wfm will be included in a
User Report Generator set of programs that will be placed in
the Library when it is ready. |
v5.x and v7.01
|
It is natural to assume that lines of code carrying out a succession of data manipulation tasks will be processed in sequence. In DOS yes but in Windows not necessarily. Consider this example from v7.01 function RRADDBUTTON1_onClick If Form.NoteNo > 5 // Notebook may not be on pages 6 or 7 when Adding
- call function to check and
change page if necessary. Also checks that current row is saved Endif // call function to BeginAppend, disable Navigation
buttons, enable fields etc. What actually happens is that NOTEBOOK1_OnSelChange() runs after RRADDBUTTON::OnClick() has completed, not before. So it sees the new blank record and immediately saves it. This prevents the user from selecting a Cancel button and gradually accumulates blank records in the table. The solution was to have a new function, similar to NOTEBOOK1_onSelChange() that in this case just changed the notebook page without doing a save. It did not then matter whether it was processed before or after. A similar but more complex situation has been seen in v5.5. In this instance a SEEK was attempted before some earlier code had created the index! The solution here was to divide the processing code into sections, do each section from a Case ... statement, the whole inside a loop that incremented a counter so that the Do Case called a fresh section on each loop. It is worth watching out for occurrences of this kind. The
effects or the cause of any errors are not obvious and can prove
very frustrating. |
v5.x - Converting Fox to dBASE - Indexes |
Fox has an instruction for deleting all indexes. How is this done in dBASE? Each index has to be deleted in turn, and then re-created. A program called CREINDEX on the dBASE Forum automatically extracts index information from a table, deletes the indexes and re-creates them. One member recommends that each project should have its Re-Index
program which contains the necessary code to delete and recreate
all indexes. |
v5.x - Changing the number of tabs on a TabBox |
The number and tabs on a TabBox can be changed at any time simply by changing the TabBox.DataSource, eg form.tabbox1.datasource = 'ARRAY {"TABBOX1","Tab 2"}' If the number of tabs is reduced, the original pages are not lost, and can be recovered by re-setting the datasource at a later time. Remember to set Form.page to the desired page before
starting, and use the OnLeftMouseUp event of the TabBox
to set the page number, eg |
|
|