Correct Syntax???!!!

J. Landman Gay jacque at hyperactivesw.com
Fri Mar 24 16:15:53 EST 2006


David Burgun wrote:

>>   on preOpenCard
>>       repeat with i = 1 to the number of flds
>>         if the lockText of fld i is false then
>>            put empty into fld i
>>         end if
>>       end repeat
>>       pass preOpenCard
>>   end preOpenCard
> 
> 
> Yes, but this only works for fields and it only works on *all*  fields, 
> what if you wanted to leave the field untouched from the last  time it 
> was used.

I think the main point is that you can structure this handler any way 
you need to in order to accomplish a generic goal. You don't necessarily 
need to change every field's contents; the handler can check for a field 
property, field contents, a list in a global variable, anything at all, 
and only act when appropriate. There could be default values, updated 
values, values based on a calculation, no value changed, whatever you 
need. It doesn't have to be only fields; you can use the more generic 
"control" keyword and check everything on the card. The idea is that one 
or a few handlers in a central location manage everything. The script 
becomes universal and transportable.

> Maybe a better example is this. I have a preferences stack, one of  the 
> items on it is the unit of measurement, it can be set to MM, CM  or 
> Inches. I have a couple of groups in my Group Library to do with  
> measure. One of them has the following fields:
> 
> [] = a field
> <> = variable value
> 
> [Width:]   [ <value_in_units>]   [<Units>]
> [Height:]  [ <value_in_units>]  [<Units>]
> 
> If the units were set to CM and the values were 100.
> 
> Now the user opens the preferences stack and changes the units to MM.  I 
> want all <Units> values to change from CM to MM and I want 100 CM's  to 
> now be 1000 MM's.
> 
> Using ISM, I would do this in the script for the Value and Units fields:
> 
> ListenForMessage("PrefsMeasureUnits",kMeasureUnits)
> 
> and define the following handlers for the <Units> fields:
> 
> on PrefsMeasureUnits theMessageID, theSubClass, theUnitValue
> set the text of the long id of me to theUnitValue
> end
> 
> and on the <value_in_units> fields:
> 
> on PrefsMeasureUnits theMessageID, theSubClass, theUnitValue
> put CalcualteNewValue(the text of the long id of me, theUnitValue)  into 
> myNewValue
> set the text of the long id of me to myNewValue
> end
> 
> And in the script of the popup menu in the preferences stack, I'd write:
> get ISMPutMessage("PrefsMeasureUnits", kMeasureUnits,theNewUnitsValue)
> 
> And any object in any card on any stack can "listen" for the message,  
> so they all initialize to the correct value. I therefore only need to  
> change the value once, not once for each object.

I think we all do something very similar in most of our stacks, it is a 
very common goal. And since you now have your method working, there's no 
point in changing it. But for those who may be curious, I'd accomplish 
the goal differently and, I think, with less work and far fewer scripts.

I would use Revolution's native system messages to trigger a handler 
which is located in the stack script, the background script, or a 
library script. The system message I'd trap depends on the situation, 
but in this case a preOpenCard message would allow the fields to change 
their content before the card is displayed. Instead of adding a script 
to each field (unnecessary overhead,) I would mark the field in some way 
as "special"; set a property, or (more typically for me) preface the 
field name with particular string. It doesn't matter how these fields 
are differentiated, it only matters that a script can test for the fact 
that they are controls that need to be handled.

Then in my library/stack/background script, I'd have a handler:

on preOpenCard
   doCalcStuff
end preOpenCard

on doCalStuff -- all actual work goes here
   repeat with x = 1 to the number of controls -- or "flds","btns", etc.
     if the uUpdate of control x then <whatever>
   end repeat
end doCalcStuff

A doCalcStuff handler would check the Preferences stack to see what the 
user's measurement preference is, and re-calculate those fields that 
require it before the card opens. It can update both the measurement 
popups as well as the data calculation fields at the same time.

You get the same results, with less scripting and more portability. In 
addition, the fields themselves do not need to take any kind of active 
"listening" role at all, nor do they need any particular scripts; they 
need do nothing. All the updating is handled in a single place -- a 
backscript or similar -- and if you need to change the behavior you only 
need to change the backscript.

The effort required to change a measurement preference is identical to 
the method you are currently working with. The user makes only a single 
selection in the Preferences stack, and in fact no other actions take 
place at that time. There is no performance hit because the actual 
updating doesn't happen until the card is displayed, where the update is 
virtually instantaneous.

Now, I think I know what you will say: what happens if you do need 
everything to update all at once? No problem. You can do that by writing 
your handler to trap a different trigger; for example, trap preOpenStack 
to loop through the cards and run the doCalcStuff handler on each one 
when the stack first opens, or trap preOpenBackground to do the same for 
only a subset of cards. Or trap closeStack in your Preferences stack and 
run the doCalcStuff then; that way when the prefs stack closes, all the 
fields, buttons, controls, whatever are updated when the user changes 
preference settings.

The result is just what you have described, if I understand your method 
correctly. And there is only one script to manage it all. The objects 
themselves need nothing more than a property or a name, and in many 
situations they don't even need that. Sometimes a generic check is all 
you need; i.e., checking to see if the field contains a number, or if 
its owner is a particular group, or if its backgroundcolor is green, or 
its short name is "lbl" (one of my favorite tests, I use it all the time 
to update object labels on the fly.)

> I don't need to open the script editor either! And if I delete an  
> object then messages just stop being sent to it!

The same applies to the above approach. You would need to open the 
script editor if you wanted to change the way doCalcStuff works, in 
either of our methods. With the above approach, a non-existent object 
can't possibly be dealt with in a handler that specifically works with 
existing objects.

> ISM is a library so I am using this technique.

Most libraries do not rely on anything but themselves; if your system 
requires that every object have its own "listening" handler, then it 
isn't really a library, it's more of a whole development system. I would 
think this would be less portable than a true library, which is 
generally comprised of only a single script that does not rely on the 
state of any other objects.

I really don't know
> anything about front or back scripts, and to be honest the lack of  good 
> documentation has put me off looking at them. 

These seem to be pretty well covered in the docs, though the concept is 
so simple there isn't much to say about them. Look up the "insert" 
command for starters. A backscript allows you to insert any script you 
like into the message hierarchy, and is typically how libraries are 
implemented. They allow you to manipulate the message hierarchy at will 
and make use of Revolution's native message passing rules rather than 
trying to add a secondary system on top of the existing one.

Apologies for the long message. As I said, since you have your method 
working now, the above is mostly for anyone who may be interested in a 
more standard xtalk approach.

-- 
Jacqueline Landman Gay         |     jacque at hyperactivesw.com
HyperActive Software           |     http://www.hyperactivesw.com



More information about the Use-livecode mailing list