LiveCode Concepts

Got a LiveCode personal license? Are you a beginner, hobbyist or educator that's new to LiveCode? This forum is the place to go for help getting started. Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller

Post Reply
tjm167us
Posts: 50
Joined: Sat Dec 03, 2011 8:27 pm

LiveCode Concepts

Post by tjm167us » Thu Dec 15, 2011 10:01 pm

Good afternoon everyone,
Recently, I have become more familiar with the LiveCode documentation (the users manual, dictionary, and lessons/tutorials) and have noticed the following thing:

The documentation seems satisfactory to learn how to use the language, but not why/how certain features are useful!

I was hoping that this thread can be a place for people to post resources, and/or replies to questions about things like:
1) How does the message path work, and why is it so awesome?!
2) What would compel someone to want to use custom properties? - They are custom, so you know they MUST be good, right?
3) Why the heck are behaviors neat, and what are the limitations of how you can use them?
4) We know Groups and Backgrounds are mentioned in user manual, but practically, what do they allow you to do?

Who knows, maybe I'm way off base here, and maybe there is another resource that I just don't know about, but I imagine I'm not the only one with this sort of problem.

So, to start things off, I came across a very well written article by Richard Gaskin at Fourth World that did a *GREAT* job explaining the tools available to extend the message path (and how those tools fit into the message path). It is a must read for anyone new to LiveCode!

http://www.fourthworld.com/embassy/arti ... _path.html

I look forward to hearing from you all, especially you guys with experience that can help shorten the learning curve of us newbies!

Cheers,
Tom

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: LiveCode Concepts

Post by mwieder » Thu Dec 15, 2011 10:45 pm

Whew! That's a lot to cover in one thread!

Lemme take a stab at starting off just one of your topics and talk about behaviors.

I think of behavior objects (they're limited to being buttons at the present) as a local backscript (and you can look up backscripts in Richard Gaskin's article). They don't really introduce anything earth-shakingly new, just a side-trip in the message path. In other words, if I put a function foo() in a behavior button and then set the behavior of a control to the long id of that behavior button, the foo() handler will be in the message path for that control. And not for other controls whose behavior is not set to that button.

Now comes some of the fun part. You can have multiple controls whose behavior is set to the same behavior button. This allows for a form of object-oriented inheritance - by changing the code in the behavior button you can change what happens in a set of controls that are linked to that behavior button. The datagrid control makes extensive use of behaviors to good effect.

You can override behavior handlers in your controls if you want local control and then pass the message on or not. This again is quite object-oriented and is about as close as we can get right now to real subclassing.

If you reference "me" in a behavior script the me is automatically converted to the object that referenced the behavior button, not the behavior button itself. And the use of "dispatch" with no object (as in "dispatch someMessage") will send the message from the behavior button to the calling control, counter to the normal flow of messages. This is very powerful and is LC's equivalent of ruby's "yield" command.

Behavior button scripts are reentrant - local variables in a behavior script are instantiated in the calling control rather than the behavior utton in true multiuser fashion, so that calling a behavior function from multiple controls doesn't overwrite local instances.

There are some drawbacks. You can't have multiple levels of behavior buttons. That is, you can't expect to set the behavior of a behavior button and have messages trickle down the message path that way. One level is all you get. At least for now.

There's nothing you can do with behaviors that can't be done in other ways. But behaviors make a neat package for localizing and reusing code in an elegant and maintainable way.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: LiveCode Concepts

Post by mwieder » Thu Dec 15, 2011 10:55 pm

(I couldn't resist one more)
What would compel someone to want to use custom properties? - They are custom, so you know they MUST be good, right?
ROTFL. Custom properties are just properties that haven't been defined by the system (leaving aside a discussion of custompropertysets, which could get into a longer thread). Nothing more complicated than that.

You can already set some properties of an object:

set the backColor of button x to "blue"
set the text of field "foo" to "hello, sailor"

where the BNF form is something like "set the <property> of <object> to <value>"

If <property> is one of the properties that's already defined for you, then it gets set and you're done.
If not, then that property gets assigned to the object and you're done.

set the PropertyThatIJustMadeUp of field "foo" to 3.1416

Now you can

put the PropertyThatIJustMadeUp of field "foo"

and you'll get 3.1416
If you open the property inspector and look at Custom Properties of field "foo" you'll now see PropertyThatIJustMadeUp defined as 3.1416.

And you'll find that you can stuff anything you want into custom properties: rants, scripts, controls, even whole stacks.

Bernard
Posts: 351
Joined: Sat Apr 08, 2006 10:14 pm

Re: LiveCode Concepts

Post by Bernard » Sun Dec 18, 2011 9:43 pm

2) What would compel someone to want to use custom properties? - They are custom, so you know they MUST be good, right?
Think of custom properties as variables that maintain their state between your application being started and stopped (provided the stack in which they are stored in is saved to disk when the app stops).

They are useful for storing e.g. SQL statements, or configuration parameters, or preferences. Through the inspector, there is a visual interface to these values, without storing them within a script itself. Without custom properties, you'd need to hard code values into a script. Or else use an ini-file or somesuch, and store the values there.

Custom properties can also be used to store binary data. Thus, some people actually store entire stacks inside the custom properties of another stack. Some people stored a sqlite db inside the custom property, and move it to the filesystem as part of an application's installation or initialization.

The whole of the DataGrid is basically configured by setting custom properties.

Bernard
Posts: 351
Joined: Sat Apr 08, 2006 10:14 pm

Re: LiveCode Concepts

Post by Bernard » Sun Dec 18, 2011 9:45 pm

4) We know Groups and Backgrounds are mentioned in user manual, but practically, what do they allow you to do?
Groups allow you to group other controls together (backgrounds are a sub-species of Groups). The DataGrid is in fact an aggregation of many basic controls into a new form of control.

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: LiveCode Concepts

Post by mwieder » Sun Dec 18, 2011 9:58 pm

If you group a set of radio buttons, they will act the way you expect radio buttons to behave: only one button in the group can have a highlight, and you can query for the "hilitedButton of group x".

FourthWorld
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10049
Joined: Sat Apr 08, 2006 7:05 am
Contact:

Re: LiveCode Concepts

Post by FourthWorld » Sun Dec 18, 2011 10:42 pm

Thank you for the kind words about my Message Path article.

The others here have handled most of the items in your list well, so I'll try my hand at the lonely #3:

Why the heck are behaviors neat, and what are the limitations of how you can use them?

Behaviors rock!

They streamline a great many situations that would require either replicated code or if-thens in a frontScript, simplifying your code while offering better performance than alternatives (see http://lists.runrev.com/pipermail/use-l ... 21212.html).

With a behavior script you can define code for any number of objects in one place, so enhancing and maintaining that code becomes much easier.

For example, if you need fields that validate input, without behaviors you have two alternatives:
A) Replicate the code within the script of each object
B) Put the code in a frontScript to trap the closefield message

With option A you're doing a lot of copy-n-paste every time you modify the script.

With option B that'll trigger for all objects you'll also need some sort of flag for those objects you want the script invoked for. You could use a custom property for that, but it's just one more if-then to keep track of, adding complexity, and you'll have to be careful to use "the target" when evaluating the objects to make sure you get the right ones.

With behaviors, you just assign the behavior object to the fields you want affected one time, and from then on they'll use that script for message handling.

To make it even easier, "me" within a behavior script always refers to the object using the behavior script rather than the object containing the behavior script, so you can write your code as easily as you would if it lived in the target object.

And even better, any script-local variables used in the behavior script are maintained separately for each object using the script, so you can have any number of objects using something like:

Code: Select all

local sOrigVal
on openField
   put the text of me into sOrigVal
end openField
...and the value of sOrigVal will be unique to each object using that script.

Need one field to behave differently for a handler than the others, but still want to use the behavior script for all the other messages? No problem: the behavior script comes into play after the object's own script, so you can trap a message there to handle for that object, and pass the message or not as you like so you can both overload and override behaviors.

The more you use behaviors the more you'll want to use them for all sorts of things. For example, in conjunction with the "selectGroupedControls" group property you can use behaviors to easily craft all sorts of custom controls. Indeed, the DataGrid is an excellent example of that, using a pair of behavior scripts (one for the DataGrid as a whole and one for its row template) to drive everything it does.

Behaviors aren't quite as flexible as a true OOP implementation, but they're pretty close. Perhaps the biggest limitation is that currently we can only assign one behavior to an object, and the behavior itself cannot use a behavior, so nesting which might provide subclassing is not allowed.

If you really need two-level-deep behaviors, in the current implementation you can work around this limitation by putting a control within a group, and having the control itself assigned to one behavior and its group assigned to another, which would give you a message path like this:

control
control's behavior
group
group's behavior
card
stack
(etc)

Behaviors have completely changed my coding style, providing a lot of the benefits of OOP in terms of maintenance and reuse.
Richard Gaskin
LiveCode development, training, and consulting services: Fourth World Systems
LiveCode Group on Facebook
LiveCode Group on LinkedIn

tjm167us
Posts: 50
Joined: Sat Dec 03, 2011 8:27 pm

Re: LiveCode Concepts

Post by tjm167us » Wed Dec 21, 2011 4:58 pm

Thank you all for posting!
Regarding behaviors: I currently have some libraried routines that I call with particular parameters in the applicable handlers for each text field I'm formatting. So, before learning about behaviors, I would format text fields the following way:

In my TextFormattingLib, I have three formatting functions:

Code: Select all

function checkForValidInput pFieldName, pKeyPress, pFieldType
--My code for determining whether a keyPress is valid
end checkForValidInput

function formatTextField pFieldName, pFieldType
--My code for adding/removing formatting characters as the user enters text
end formatTextField

function cleanUpFormatting pFieldName, pFieldType
--Does final cleanup after the user is done entering data
end cleanUpFormatting
In the mainstack of my application I open my library for use:

Code: Select all

on preOpenStack
start using stack "TextFormattingLib"
end preOpenStack
And finally, in each of my text fields, I have (in this case, it's "MyField"):

Code: Select all

 on keyDown theKey
if (checkForValidInput "MyField", theKey, "Currency" = true) then
pass keyDown
else
beep
end if
end keyDown

on rawKeyUp
formatTextField “MyField”, “Currency”
end rawKeyUp

on exitField
cleanUpFormatting “MyField”, “Currency”
end exitField
 
So, although, it is not the most elegant solution, I generalized my text field formatting to a point of only having to copy and paste the handlers from one text field to another, and change the parameters used for my library functions.

Now, with behaviors, I see how I can drastically reduce the work I have to do, but I’m a little unsure of where to place each part.

I know I need to:
1. Load the stack with the “format text field” behavior button into program memory before anything tries to use it.
A logical place to put the behavior button would be my “TextFormattingLib” stack, so the behavior button will be loaded into memory on preOpenStack (just like my library functions).

But, let’s say for a second I didn’t have a library of functions, but rather just a stack with my behavior buttons. Is there another way of loading that stack into memory without putting it into the message path? Also, am I going to run into trouble because my behavior is trying to use a library function that I haven’t yet reached in the message path?

2. Set the behavior for every text field to my “format text field” button
Would I also do this in the preOpenStack handler of my applications main stack? Could I create an array of text fields that I am using in my application and just set up a repeat to set all of these behaviors?

3. Create a custom property that my behavior can use to know what type of text field it is to format
This would eliminate the need to pass parameters to my library functions. But which handler would I set this property in the text field?
I really need to learn how to ramble less!
Tom

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: LiveCode Concepts

Post by mwieder » Wed Dec 21, 2011 6:48 pm

Tom-

Here's one way to deal with this:

1. at design time, define a custom property for each field thusly

Code: Select all

set the fieldType of field "MyField" to "currency"
2. create a new button for the behavior script. call it something like "btnFieldBehaviors"
3. set the field's behavior to the button

Code: Select all

set the behavior of field "MyField" to the long id of button "btnFieldBehaviors"
4. in the behavior button's script put

Code: Select all

-- no need for the field name here, you can just use "me"
-- no need to pass the field type, you can get it from "the fieldType of me"

    on keyDown pKey
        if (checkForValidInput  pKey) then
            pass keyDown
        else
            beep
        end if
    end keyDown

    function checkForValidInput pKeyPress
    --My code for determining whether a keyPress is valid
    -- if the fieldType of me is "currency" then
    -- else
    -- end if
    end checkForValidInput

    on rawKeyUp
    --My code for adding/removing formatting characters as the user enters text
    end rawKeyUp

    function exitField
    --Does final cleanup after the user is done entering data
    end exitField
5. Now set the behaviors of the other fields to point to the same behavior button
6. Remove the keyDown, checkForValidInput, rawKeyUp and exitField handlers from the field scripts.
7. You're done. No library stacks to load, nothing else.

tjm167us
Posts: 50
Joined: Sat Dec 03, 2011 8:27 pm

Re: LiveCode Concepts

Post by tjm167us » Wed Dec 21, 2011 7:03 pm

Mark,
Thanks for the response -- I have a couple of questions regarding your last post.

What if I want to use this in multiple different applications? Would I then instead create this behavior button in a seperate stack (a library) and load that stack in the preOpenStack handler of whatever application I want to use it? If so, would I use the "start using stack "myBtnBehaviorStack"", or is there a way of loading the stack into memory without inserting it into the message path?

In what handler would you recommend to setting the custom property of that text field? Or would you just use the tool palette to define the custom property?

Thanks!
Tom

mwieder
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3581
Joined: Mon Jan 22, 2007 7:36 am
Contact:

Re: LiveCode Concepts

Post by mwieder » Wed Dec 21, 2011 7:17 pm

What if I want to use this in multiple different applications? Would I then instead create this behavior button in a seperate stack (a library) and load that stack in the preOpenStack handler of whatever application I want to use it? If so, would I use the "start using stack "myBtnBehaviorStack"", or is there a way of loading the stack into memory without inserting it into the message path?
Hmmm. Well, behaviors use the long id of the behavior button (technically the "rugged" id, but that's splitting hairs for this discussion), so as long as the stack with the behavior buttons is in memory it doesn't have to be in the message path. But "start using" is no doubt the easiest method of doing what you want. My preference would probably be just to copy the behavior button to the new stack, but I can see advantages in some situations for wanting the behaviors in a shared stack.
Or would you just use the tool palette to define the custom property?
Yep - that's how I'd do it. Just remember to type in "the long id of", as in 'the long id of button "xyzzy" of stack "MyStack"'

marksmithhfx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 931
Joined: Thu Nov 13, 2008 6:48 am

Re: LiveCode Concepts

Post by marksmithhfx » Sun Jan 22, 2012 7:23 am

Mark, Richard, how do you handle the situation where the stack where the behavior buttons are located gets moved or renamed? (it would be nice if the path to the behavior scripts was coded in a "relative" way as opposed to an "absolute" way... I think)

-- Mark
macOS 12.6.5 (Monterey), Xcode 14.2, LC 10.0.0, iOS 15.6.1
Targets: Mac, iOS

Post Reply