Saturday, February 20, 2010

Doing Math with Strings in Actionscript, General Type Casting

     I have been getting some calls about addition not working with point values from Inetsupervisor. I have no way of knowing what type of value that will be sent to the connector so I assign conn.output as a string type so I can handle all form of data values. In AS2.0 most all values that are generic objects or just are not explicitly typed are implicitly cast to string. So if you need to do addition, and 1 or more object is a string then, explicitly type cast them to the Number.

Example:
a = status_txt.text + 15; //add the values of text box and 15. If the text is 1 but the all text is cast as string so a string concatenation will happen
trace(a);// value is 115. Bad


a = Number(status_txt.text) + 15; //add the values of text box and 15. The text value is still 1 but I have cast it to a number. 2 numbers will do math operations
trace(a);// value is 16. Good


    This is most common casting you will have to work with, but sometimes you need to insert a number to a string:

var num:Number = 5;
a = "Hello all " + String(num) + " of you"; //num is a typed as a number with the value of 5 so it needs a cast to do string concatenation
trace(a);// Hello all 5 of you. Good


    So since all values in AS are based as generic objects they all can be cast to some other type when needed.

Labels: , ,

Thursday, November 26, 2009

Debugging flash movies with trace()

When we start making custom flash for Inetsupervisor they tend to be small and relatively easy, but as we become more comfortable with flash we start to test our programming chops and want our little movies to behave more like apps with all the bells, whistles, functionality and bugs that go along with that. I have been using a plugin for firefox called Flash Tracer for a while and have found it very useful. Flash Tracer works with the trace function in flash, some of you may not know what the trace function is so here is an explanation straight from Adobes website:

trace
Availability
Flash Player 4.
Usage

trace(  expression  ) 
Parameters
expression An expression to evaluate. When a SWF file is opened in the Flash authoring tool (via the Test Movie command), the value of the expression parameter is displayed in the Output window.
Returns
Nothing.
Description
Action; evaluates the expression and displays the result in the Output window in test mode.
Use trace to record programming notes or to display messages in the Output window while testing a movie. Use the expression parameter to check if a condition exists, or to display values in the Output window. The trace action is similar to the alert function in JavaScript.
You can use the Omit Trace actions command in Publish Settings to remove trace actions from the exported SWF file.
Example
This example is from a game in which a draggable movie clip instance named rabbi must be released on a specific target. A conditional statement evaluates the _droptarget property and executes different actions depending on where rabbi is released. The trace action is used at the end of the script to evaluate the location of the rabbi movie clip, and display the result in the Output window. If rabbi doesn't behave as expected (for example, if it snaps to the wrong target), the values sent to the Output window by the trace action will help you determine the problem in the script.
on(press) { 
  rabbi.startDrag(); 
 } 

 on(release) { 
  if(eval(_droptarget) != target) { 
     rabbi._x = rabbi_x; 
     rabbi._y = rabbi_y; 
  } else { 
   rabbi_x = rabbi._x; 
   rabbi_y = rabbi._y; 
   target = "_root.pasture"; 
  } 
  trace("rabbi_y = " + rabbi_y); 
  trace("rabbi_x = " + rabbi_x); 
  stopDrag(); 
 }


as you can see the trace function will take an object value and then write it as text. In this case Adobe is talking about displaying the text in the output window of the flash program during a debugging session, but what about when you are vieing it on a webpage. This is where Flash Tracer comes to the rescue. Flash Tracer will capture the text coming out of the trace() and display it on a window in your browser.

Before I begin to show you how to use trace() and the Tracer you will need to setup your machine. First and foremost Firefox will have to be on the machine, second get Flash Tracer plugin for Firefox, then third you'll need a debugging version of flash player. Once you have all that downloaded and installed then we need to setup Flash Tracer.
Start Firefox and then Tracer by going to Tools --> Flash Tracer when it is running click on the wrench icon on the lower right for preferences. At the top you will see Select File Output depending on you operating system this file will be located in different locations, just follow the defaults for you OS and you should be fine. The rest of the preferences you can leave as the defaults as they are mostly styling.


Next lets write some code to show how this works. Make a movie then add the following code:

setInterval(funct,1000);//repeating timer to run a function set at 1 second
var inc:Number = 0;//conting variable
function funct()//function that is called by the repeating interval
{
trace(inc++);//increase the value of inc and output the value to the trace
}

Build the movie, insert into a webpage, and as you can see now when we run the movie with Flash Tracer every second the value of inc gets updated and ported to the text. You can forward the value of anything to the trace() strings, numbers, names or you can use it to confirm actions have happened like when a button is clicked. I hope this helps/encourages more and better flash development

Labels: , ,

Thursday, April 9, 2009

Flash Movie to send multiple, user defined values

Most of the time everybody works with the standard override values, ON - OFF or some setpoint value, but what if we need something more. What do you do if you made you own variable that does 3 or more functions. Plus what if we need to change the output based on the type of equipment. We will focus on a movie that has 3 buttons and will send a different user defined value depending on which button is clicked. In addition I will show you how to add and use EventListener's.

First start a new movie, drop a connector component and 3 buttons. Give everybody an instance name and assign the ID to the connector.

con.ID = PointID; // Assign the point ID to work with

Then we will add some code to change the button labels just incase the defaults don't jive with what we are tring to do.

//This runs to find if any params called names exist if it does then use it to change the names of the buttons
//names must be a comma delimited string of names
if (names != undefined){//param names exist
var button_names:Array = names.split(',');//split the string by comma's
button1.label = button_names[0];//assign first object
button2.label = button_names[1];//assign second object
button3.label = button_names[2];//assign third object
}

Now we need to make a variable to hold our output values then fill it up with some values

var output_values:Array = new Array();//create an array to hold the output values

If the prameter outputvalue exist then parse it and fill the array

if (outputvalue != undefined){
var outputValuesTmpArray:Array = outputvalue.split(',');
output_values[0] = outputValuesTmpArray[0];
output_values[1] = outputValuesTmpArray[1];
output_values[2] = outputValuesTmpArray[2];
}
else{//no user defined output values so assign some default values
output_values[0] = "0";
output_values[1] = "1";
output_values[2] = "2";
}

Your default values can be anything I would suggest your most common used values, so you don't have to override them as much.
Next all that is need is the code to send the value when the button is clicked.

button1.addEventListener("click",button1_listener);//create a listening function for the click event of button 1
function button1_listener(evt){
con.sendOverride(PointID,output_values[0]);//when button 1 is clicked send the 1st value of the output_value array
}

button2.addEventListener("click",button2_listener);//create a listening function for the click event of button 2
function button2_listener(evt){
con.sendOverride(PointID,output_values[1]);//when button 2 is clicked send the 2nd value of the output_value array
}

button3.addEventListener("click",button3_listener);//create a listening function for the click event of button 3
function button3_listener(evt){
con.sendOverride(PointID,output_values[2]);//when button 3 is clicked send the 3rd value of the output_value array
}

stop();//stop at this frame


Normally I would have you place the con.sendOverride function inside the button using the on(click) method and use the _parent scope, but I thought this would be a good opertunity to show you EventListeners. All objects(buttons, text, graphics...) fire events when they do things (mouse click|up|down|over, change,resize...) and if you what to do something when this happens you can attach a listener function to fire when the event happens. In the case of button1, we attached the function button1_listener to the "click" event, so when the "click" event fires button1_listener will "hear" it and then run. When the button1_listener function runs we send out the value of output_value[instance 0]. This can be used to make graphics into buttons or do something while typing...

Next just place the movie on your web page and set the PointID then names value with a comma delimited string (ie names=hand,off,auto) if you need, and do the same with outputvalue (ie outputvalue=ST_LOW,ST_MED,ST_HIGH or outputvalue=100.0 1,0.0 0,0.0 -1). If you need more then 3 options you can just add more buttons and use the next array value instance or maybe use a combobox or different type of UI to scale it up.

You can download the source and compiled here.

3_Button.rar

Labels: , ,

Friday, January 2, 2009

DreamweaverCS4 AC_FL_RunContent Script Compatibility

The CS4 version of DW does not support or use AC_FL_RunActiveContent script for flash movies anymore. If you remember This script was used to stop the ActiveX hash box in Internet Explorer 6 and 7. This had not been nessisary for IE since an update in the first part of 2008.

If you have made pages with DW8.02 or CS3 and have the "Insert Browser Safe Script" option check then you have seen this script generated. When (or if) you transfer to the CS4 version of Dreamweaver and you work with the older web pages the flash movies will not update any changes you will make. This is caused by the fact that the AC_FL_RunActiveContent script actually creates and loads the flash movie for you from javascript and CS4 does not update the information in the script as it does in the object, so when you load the movie only the old information is loaded. There are 2 options to fix this issue:
  1. Remove the script by hand
  2. Modify Dreamweaver to update the scripting
We will start with option 1. When looking at the flash movie in "code" design you will notice the object is wrapped in noscript tags. This is used to tell the browser not to generate the information inside of these tag's. So the only thing generated by the browser is the content created by the AC_FL_RunActiveContent script above it. When you modify the object tag, dreamweaver use to automatically match the script above it. This is no longer done. To remove the javascript you must delete everything inside and including the script tag's al well as the noscript tag's so the browser will generate the movie content. This can be done on a site wide basis easily using dreamweavers find and replace utility. Once the scripting has been removed the object will be generated on it's own with all of the new or modified options applied.

Option 2 is much easier. If you shutdown dreamweaver first then take the files from:
%windir%:\Program Files\Macromedia\Dreamweaver 8\Configuration\ActiveContent\Converters
if you were working with DW8, or
%windir%:\Program Files\Adobe\Adobe Dreamweaver CS3\configuration\ActiveContent\Converters
if you were working with CS3 and put them in
%windir%:\Program Files\Adobe\Adobe Dreamweaver CS4\configuration\ActiveContent\Converters
When you start up dreamweaver and modify a flash movie the RunActiveContent script will be updated just like CS3 or DW8.02. There should be 6 files in the old DW folder:
  1. ActiveContent.js
  2. ActiveContent.xml
  3. ActiveX.htm
  4. ActiveX.js
  5. Adobe.htm
  6. Adobe.js
all 6 need to be moved and if the new folder has the file ActiveContent.xml already in it just override the new one.

This is only needed if you are making changes to pages originally made from older DW's with the browser safe script option enabled, it is not necessary for new aspx pages made because the RunActiveContent script is not generated. I have included a copy of the missing files.

Converters.rar The missing files

http://www.inetsupervisor.com/Support/default.htm “InetSupervisor SUPPORT”

http://www.inetsupervisor.com/Products/Default.htm “Quark Communications PRODUCTS”

http://www.inetsupervisor.com “InetSupervisor HOME”

Labels: , , ,

Thursday, August 28, 2008

Enumerated variables

Enumerated variables or types are data multiple data “chunks” grouped together into one piece of information. The 2 main reasons for enumerated data are

  1. Controllers that are limited in the amount of variables they are allowed to expose to the network.

  2. Network commands that require more then a simple ON|OFF or analog value.

The data is delimited in some way to recognize the individual parts, like a comma or carrot. This delimiter is what we will use to parse out some data, work with the individual parts, then reassemble the data and send it back to the controller.


In this example we will be working with a LonWorks UNVT made by the Distech company. The process would hold true for any enumerated data from any protocol once it has been imported into the Atlas database. This variable is used to modify or override the internal vars and physical input and output values in the controller. The variable has 4 parts separated by white space(aka empty char). The first is the type field, this is a string that specifies what type of var to override. Second is the index of the type field, this is a unsigned short. Third is the mode, another string specifying manual or automatic operation. The last is the value to be applied to the overriding var it is a signed long.



//////////////////////////////////Code//////////////////////////////////////////////////////////////////////////////////////////////////



_global.style.setStyle("themeColor", "haloBlue");//change the style

/*********************Initilize the local vars************************************/

con.ID = PointID;// Assign the point ID to work with

var output_timer:Number = setInterval(evaluateOutput, 3000);// Set timer to display updated values

var type:String = "";

var index:Number = 0;

var md:String = "";

var val:Number = 0;

var overrideVal:String = "";

var sentOverride:Boolean = false;

/******************Start the UI not edible until a good value comes in***********/

IntValType.enabled = false;

Index.enabled = false;

Mode.enabled = false;

Value.enabled = false;

Send.enabled = false;




The first bit of code just sets up the “theme” for the movie, internal variables to handle the parsed data, and disables the UI for now. By the way I am using 2 number steppers for the index and value, 2 combo-boxes for the type and mode and a button for sending the override value for my UI.




//********************* Main body functions ***************

function evaluateOutput(){

if (!sentOverride){//make sure we are not sending an override or making one

if ((String(con.output).indexOf("?") == -1) && (con.output != undefined)){//check for a good connection to the controller and a valid value

type = String(con.output).split(" ")[0];//load the public var

IntValType.text = type;//update the ui

index = Number(String(con.output).split(" ")[1]);

Index.value = index;

md = String(con.output).split(" ")[2];

Mode.text = md;

val = Number(String(con.output).split(" ")[3]);

Value.value = val;//update the ui

}

else if (String(con.output).indexOf("?") > -1){//updat ethat the controller is not communicating

IntValType.text = "Error";

Index.value = 0;

Mode.text = "Error";

Value.value = 0;

}

if (con.isNew == "1"){//if the val is new then allow the ui to work

IntValType.enabled = true;

Index.enabled = true;

Mode.enabled = true;

Value.enabled = true;

Send.enabled = true;

}

}

else if(con.output == overrideVal){

sentOverride = false;

type = String(con.output).split(" ")[0];//load the public var

IntValType.text = type;//update the ui

index = Number(String(con.output).split(" ")[1]);

Index.value = index;

md = String(con.output).split(" ")[2];

Mode.text = md;

val = Number(String(con.output).split(" ")[3]);

Value.value = val;//update the ui

IntValType.enabled = true;

}

}

stop();//stops the continuation of frames



In my main function I first check to see if I should pause the updating of the UI because we are in the process of making or sending an override and that the connector has a value and the value is not ??? because the drive cannot connect with the controller. If that is good then we get to the meat of this lesson. Since we know the delimiter and how many parts to expect we can now parse the data and put it into our individual vars created above. First we take the output and cast it into a string type String(con.output) then split that string with our delimiter String(con.output).split(“ “). The data will now be in an array of parts and we can then choose the piece to grab and assign to the internal var type = String(con.output).split(“ “)[0]. Do this 3 more times assigning the appropriate piece to all of the internal vars and now you can adjust them , display them or do what ever you want with them as individuals.




//////////////////////////////////Code//////////////////////////////////////////////////////////////////////////////////////////////////



on (click){//when button is mouse clicked:

_parent.overrideVal = _parent.type+" "+String(_parent.index)+" "+_parent.md+" "+String(_parent.val);

_parent.con.sendOverride(_parent.PointID,_parent.overrideVal);//send and override with the current point ID and the override value

}



When you are done adjusting the individual vars you will need to send them back to the controller for processing. To do this you need to assemble the individuals back into the form that the controller will accept. This is done by assembling a string with the values and appropriate delimiter, and sending thru the connector. _parent.overrideVal = _parent.type+" "+String(_parent.index)+" "+_parent.md+" "+String(_parent.val); assembles the string with a “ ”(white space) between each. _parent.con.sendOverride(_parent.PointID,_parent.overrideVal); sends the override.


This could also be done without assigning the array to the individual vars and then reassembling with a for loop, but if you go that route remember that each index of the array will be a string type and other types will need to be cast before they work as expected, also keep a list of what index holds what information because tempArray[7] is not as descriptive as mode, or value, or alarm.

You can download the source and compiled here

Fx-UNVT-modify_internal_val.zip

Labels: , , ,

Wednesday, April 23, 2008

Using Multiple Points in a Flash Movie

For the most part a single point id is all that is needed to run a flash component, but what if you want to make a more complex component that say compares 2 point values to change a background- color. This can be done by adding more then 1 connector to you flash movie. A connector can only have 1 point id associated with it, but there is no limit to amount of connectors you have in the movie.


To add more connectors is easy it is the same steps as the first connector, just need to add a unique instance name and pass the point id with a unique POST variable. For example I will show how to compare a space temperature to a space setpoint and change the text box background color based on the difference. For simplicity I will assume the reader has done the exercises in the flash SDK and has a working knowledge of flash and the connector component.


  1. Setup a flash movie with a Text Input box and give the box the name of status_txt

  2. Drag and drop 2 instances of the connector component on to the movie

  3. Name the first connector conn

  4. Name the second connector conn2

  5. Add the following code to the movie to pass the point id's from the POST variables to the connector's

conn.ID = PointID;

conn2.ID = PointID2;

  1. Then add a timer and point it to a function

  2. Add this code inside of the timed function. This code will compare the 2 values and update the

    background color of status_txt

var pointValue = Number(conn.output);//assign the space temperature

var pointValue2 = Number(conn2.output);//assign the space setpoint

if (((pointValue-pointValue2)<=1) || ((pointValue2-pointValue)<=1)){

status_txt.setStyle('backgroundColor',"0xFFFFFF");//even

}

if ((pointValue-pointValue2)>1){

status_txt.setStyle('backgroundColor',"0xFF66CC");//1deg hot

}

if ((pointValue2-pointValue)>1){

status_txt.setStyle('backgroundColor',"0x00FFFF");//1deg cool

}

if ((pointValue-pointValue2)>2){

status_txt.setStyle('backgroundColor',"0xFF0000");//2deg hot

}

if ((pointValue2-pointValue)>2){

status_txt.setStyle('backgroundColor',"0x0066FF");//2deg cool

}

    status_txt.text = pointValue;

  1. Publish the flash and drop it on a web page

  2. Assign the POST variables PointID=the space temperature PointID and PointID2=space setpoint PointID. The above code is functional but not finished. Proper coding should be added for error checking and null values.


Now you have a movie that can assign more then 1 point id for any number of reasons. At this point you can see a trend happening. If you need a 3rd point just add a new connector give it a unique name and assign the point id to it, and so on for as many point id's needed for your movie.

Labels: ,

Monday, March 3, 2008

Using the flash setStyle() function

I have been asked a from time to time about how to personalize individual text area's or input boxes by developers. The answer as always is that it depends. If you have worked with flash before then you are use to the IntelliSense giving you hints as to what options are available for each UI component. This works well if you are customizing a textfield, however if you are working with a textinput or textarea box's (as most people do) the same _txt.backgroundColor and _txt.textColor show up in IntelliSense but make no change to the desired UI. Frustrating I know. The difference is the textfield is a simple display box and the textarea and textinput are pre-compiled, skinned components. That is where the setStyle function comes into play. This same function is used to modify any number of parts in just about all pre-compiled UI, but we will stick with the text for now.

SetStyle is a simple function consisting of 2 passed parameters:
1.The style name to be modified, as a string.
2.The value to change the style to, as an object.
The only hard part I have heard from people using this function is knowing what to send because there is no IntlleSence for this function, but with a little google searching and common sense you should be able to figure out what to send for each style name. For starters here is a link to help the searching
http://livedocs.adobe.com/flash/8/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00004041.html. To use the function start with the instanceName of your UI we will call it ui then just call the function ui.setStyle(“backgroundColor”, 0xFF0000) this will change the backgroundColor of the UI text to turn red, or ui.setStyle(“fontSize”, 20) will give a you a 20 sized text. The link above will list the rest of the style names but they are all used the same way. One last quick code hint, if you have a style you want all of you UI's to follow use _global.style instead of the UI instance name for the setStyle() function and have the function run up front this will affect all the UI's so there is no need to type the code in for every UI.

Happy Coding

Labels: ,