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:
> 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
> and on the <value_in_units> fields:
> on PrefsMeasureUnits theMessageID, theSubClass, theUnitValue
> put CalcualteNewValue(the text of the long id of me, theUnitValue) into
> set the text of the long id of me to myNewValue
> 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 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>
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
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
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
> 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