'개발/flex'에 해당되는 글 14건

  1. 2009.12.22 Flex for XML and JSON 9
  2. 2009.12.12 Changing the Flex ProgressBar from red -> green
  3. 2009.12.11 Creating full-screen Flex applications
  4. 2009.12.10 Using the Application.application.parameters 3
  5. 2009.12.10 Maths Functions including Random 1
  6. 2009.12.10 [Flex 3.3] DataGrid 에서 필요없는 스크롤바 없애는 방법
  7. 2009.12.10 Set the selected item for a comboBox or dataGrid 2
  8. 2009.12.07 YouTube flv 소스 가져오기 8
  9. 2009.11.20 [Flex] comboBox를 이용한 필터링
  10. 2009.11.19 VideoDisplay 컨트롤 시작해보기 1
2009. 12. 22. 10:43

Flex for XML and JSON




Beauty and brains. Flex and Java. Or is it the other way around? Who can say? What I know is that Flex and Java work really well together to create amazing Rich Internet applications (RIAs). What is Flex you ask? Flex is an open source framework that you can use to build Flash applications using the tags-based MXML language (along with ActionScript 3).

Watch: Flex for XML and JSON screen cast presented by Jack (Quicktime MOV, 33MB)

You can get started by downloading the Flex IDE, called Flex Builder, from the Adobe site (http://adobe.com/flex). Flex Builder is a commercial product, but it has a long free trial period that will give you enough time to figure out if it's worth your money. In this article, I'm going to demonstrate how to use Flex and Java together. Java will run the server. Flex will run on the client. The protocol between the two can really be anything you want. But in this case I'll use XML first, then use Javascript Object Notation (JSON), since both of those are the standards we are seeing the most in this Web 2.0 world.

Building the Server Piece

The XML example starts with the simple JSP file shown in Listing 1.

  Listing 1. xml.jsp
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
<jsp:directive.page import="java.text.*"/>
<jsp:directive.page import="java.lang.*"/>
<jsp:directive.page contentType="text/xml"/>
<days><jsp:scriptlet>
<![CDATA[
double compa = 1000.0;
double compb = 900.0;
for (int i = 0; i<=30; i++) {
compa += ( Math.random() * 100 ) - 50;
compb += ( Math.random() * 100 ) - 50;
]]>
</jsp:scriptlet>
<day>
<num><jsp:expression>i</jsp:expression></num>
<compa><jsp:expression>compa</jsp:expression></compa>
<compb><jsp:expression>compb</jsp:expression></compb>
</day>
<jsp:scriptlet>
<![CDATA[ }
]]>
</jsp:scriptlet>
</days>
</jsp:root>

This service exports some random stock data for two companies (compa and compb) for thirty days. The first company's value starts at $1000, the second at $900, and the JSP code applies a random factor each day to the values.

When I use the 'curl' client from my command line to access the service I get back something like what's shown below:

 % curl "http://localhost:8080/jsp-examples/flexds/xml.jsp"
<days><day><num>0</num><compa>966.429108587301</compa>
<compb>920.7133933216961</compb>
</day>...</days>

The root tag is the <days> tag which includes a set of <day> tags. Each of these <day> tags has a <num> tag for the day number, a <compa> value for the stock price of company A, and a <compb> tag with the stock price from company B. The values of the two stock prices change with each request as they are randomly generated.

Building the Interface

Now that we have a web service that outputs stock prices, we need a client application to view it. The first one we will build is a grid style interface that simply shows the numbers. To create the Flex project, we select Flex Project from the New menu in the Flex Builder IDE. This is shown in Figure 1.

Figure -1. The ew Flex Project dialog

From here all we need to do is give the project a name. I'll call it xmldg for 'XML Data Grid.' This will create an xmldg.mxml file that has an tag in it. We will replace this simple do-nothing application with the code in Listing 2, which does a whole lot.

Listing 2. xmldg.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"> <mx:XML source="http://localhost:8080/jsp-examples/flexds/xml.jsp" id="stockData" /> <mx:Panel title="Stock Data" width="100%" height="100%"> <mx:DataGrid dataProvider="{stockData..day}" width="100%" height="100%"> <mx:columns>
<mx:DataGridColumn
dataField="compa" /> <mx:DataGridColumn dataField="compb" /> </mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>

This xmldg application code has two primary components. The first is the <mx:XML> tag which tells Flex that there is an XML data source out there and gives it the URL. This will create a local variable called stockData (specified by the id attribute) which the <mx:DataGrid> component can use as a dataProvider.

The rest of the code is just interface. There is an <mx:Panel> object that gives a nice little wrapper around the grid. Then the <mx:DataGrid> object that shows the data. Within the <mx:DataGrid> is a set of <mx:DataGridColumn> specification objects which tells the grid what data to show.

When we launch this from Flex Builder we should see something like what is shown in Figure 2.

Figure -2. The xmldg application in action

From here we can scroll the list, resize the window, and watch the data grid change size.

To add a little filtering capability, we will update the code with an <mx:HSlider> control, a horizontal slider, which will specify on which day the grid should start the data display.

For example, if we set the slider to 6 it will only show data from day 6 onward. The code for this is shown in Listing 3.

Listing 3. xmldg2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:XML source="http://localhost:8080/jsp-examples/flexds/xml.jsp" id="stockData" />
<mx:Panel title="Stock Data" width="100%" height="100%" layout="vertical"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">
<mx:HBox>
<mx:Label text=
"Start Day" />
<mx:HSlider minimum="0" maximum="30" id="dayslider" snapInterval="1" />
</mx:HBox>


<mx:DataGrid dataProvider="{stockData..day.(num >= daySlider.value )}"
width="100%" height="100%"> <mx:columns>
<mx:DataGridColumn
dataField="num" headerText="day" /> <mx:DataGridColumn dataField=="compa" headerText="Company A" /> <mx:DataGridColumn dataField=="compb" headerText="Company B" /> </mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>

There are a few more tags, but the story remains much the same. There is an <mx:Panel> tag that contains everything. Within that is an <mx:HBox> (horizontal box) tag that includes an <mx:Label> and the <mx:HSlider> control. The slider is used in the dataProvider field of the <mx:DataGrid>.

Let's have a closer look at the dataProvider attribute:

{stockData..day.(num >= daySlider.value )}

This is using ActionScript's E4X syntax to pare down the data set to the <mx:DataGrid>control to only those tags where the <num> value in the data is greater than or equal to the slider value. Flex is smart enough to watch for the change events that come from the slider to automatically update the data grid for us.

When we bring this up from Flex Builder it looks like what is shown in Figure 3.

Figure -3. The filterable grid

From here we can adjust the slider and see how that affects the data in the grid. Figure 4 shows what happens when I set the slider to 12.

Figure -4. The slider set to 12 on the data grid

This is just a simple example of what can be done using E4X in ActionScript. The E4X syntax makes dealing with XML so easy to do that you'll never want to deal with XML any other way.

Graphing

Data grids are a bit boring, at least to me. I'm a visual guy. So let's put a graph on this thing. To do that, we create a new project called xmlgph(for XML graph) and replace the xmlgph.mxml file that is created with the code in Listing 4.

 Listing 4. xmlgph.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:XML source="http://localhost:8080/jsp-examples/flexds/xml.jsp" id="stockData" />
<mx:Panel title="Stock Data" width="100%" height="100%" layout="vertical"
paddingBottom="10" paddingLeft="10" paddingRight="10" paddingTop="10">

<mx:HBox>
<mx:Label
text="Start Day" />
<mx:HSlider? minimum="0" maximum="30" id="dayslider" snapInterval="1" />
</mx:HBox>

<mx:LineChart id="chart" dataProvider="{stockData..day.(num >= daySlider.value )}"
width="100%" height="100%">
<mx:series>
<mx:LineSeries xField="num" yField="compa" displayName="Company A" />
<mx:LineSeries xField="num" yField="compb" displayName="Company B" />
</mx:series>
</mx:LineChart>
<mx:Legend dataProvider="{chart}" />
</mx:Panel>
</mx:Application>

This code is exactly like xmldg2, but the <mx:DataGrid> control has been replaced by an <mx:LineChart> control that will display a chart of the values instead of a grid. There is also an <mx:Legend> control that will display the names of the company associated with each color of line. The two <mx:LineSeries> objects are the charting equivalent of the <mx:DataGridColumn> objects. These let the line chart know what data to display on which axis.

When we launch this from Flex Builder we should see something like what is shown Figure 5.

Figure -5. The Line Chart example

Not bad, huh? And because the <x:HSlider> control is still around, we can change the starting day of the graph just by moving the slider.

In fact, with a few small changes we can allow for the graph to show a 'window' of days by providing users with two thumbs in the slider that they can move independently. The code for this is shown in Listing 5.

 Listing 5. xmlgph2.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
<mx:XML source="http://localhost:8080/jsp-examples/flexds/xml.jsp" id="stockData " />
<mx:Panel title="Stock Data " width="100% " height="100% " layout="vertical "
paddingBottom="10 " paddingLeft="10 " paddingRight="10 " paddingTop="10 ">

<mx:HBox>
<mx:Label
text="Date Range " />
<mx:HSlider minimum="0 " maximum="30 " id="daySlider " snapInterval="1 "
thumbCount="2 " values="[0,30] " />
</mx:HBox>

<mx:LineChart id="chart"
dataProvider="{stockData..day.(num>=daySlider.values[0] &&
num<=daySlider.values[1])}
"
width="100%" height="100%">
<mx:series>
<mx:LineSeries
xField="num" yField="compa" displayName="Company A" />
<mx:LineSeries xField="num" yField="compb" displayName="Company B" />
</mx:series>
</mx:LineChart>
<mx:Legend
dataProvider="{chart}" />
</mx:Panel>
</mx:Application>

All we have done is add the thumbCount and values attributes to the <mx:HSlider> tag, and updated the dataProvider in the <mx:DataGrid> tag. Because this is XML, I had to encode some of the entities in the dataProvider. When we run this from Flex Builder we see something like Figure 6.

Figure -6. The windowed line chart

That about does it for the XML portion of the demonstration. From here I'll show you how to build a Flex application that consumes JSON services.

Building the JSON Server

Creating the JSON reading application starts with creating a JSON data source. Once again, we'll fall back on trusty JSP to build the JSON encoded data stream. The JSP code for the server is shown in Listing 6.

 Listing 6. json.jsp
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="1.2">
<jsp:directive.page import="java.text.*"/>
<jsp:directive.page import="java.lang.*"/>
<jsp:directive.page contentType="text/json"/>
[<jsp:scriptlet>
<![CDATA[
double compa = 1000.0;
double compb = 900.0;
for (int i = 0; i<=30; i++) {
compa += ( Math.random() * 100 ) - 50;
compb += ( Math.random() * 100 ) - 50;
if ( i > 0 ) out.print( "," );
]]> </jsp:scriptlet>{"compa":<jsp:expression>compa</jsp:expression>,"compb":<jsp:expres
sion>compb</jsp:expression>}<jsp:scriptlet>
<![CDATA[ }
]]>
</jsp:scriptlet>]
</jsp:root>

This is exactly like the XML service, but instead of creating XML tags we create JSON encoded data.

When I run the 'curl' utility from the command line to get the page it looks like:

 % curl "http://localhost:8080/jsp-examples/flexds/json.jsp"
[{"compa":992.2139849199265,"compb":939.89135379532}, ...]

That's just the kind of thing that a Javascript client would love to see.

Consuming JSON Services

Flex is written in ActionScript 3, the programming language of the Flash player. It's similar to Javascript, but it lacks the eval function. So how do we turn JSON text into ActionScript data? Thankfully, the free ActionScript 3 core library (http://as3corelib.googlecode.com) comes with both a JSON decoder and a JSON encoder installed.

The code in Listing 7 shows the JSONDecoder object in action.

 Listing 7. jsondg.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
creationComplete="jsonservice.send()">
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import com.adobe.serialization.json.JSONDecoder;

private function onJSONResult( event:ResultEvent ) : void {
var data:String = event.result.toString();
data = data.replace( /\s/g, '' );
var jd:JSONDecoder = new JSONDecoder( data );
dg.dataProvider = jd.getValue();
}
]]>
</mx:Script>
<mx:HTTPService id="jsonservice"
url="http://localhost:8080/jsp-examples/flexds/json.jsp"
resultFormat="text" result="onJSONResult(event)" />
<mx:Panel title="Stock Data " width="100% " height="100% ">
<mx:DataGrid id="dg" width="100%" height="100%">
<mx:columns>
<mx:DataGridColumn
dataField="compa " />
<mx:DataGridColumn dataField=
"compb " /> </mx:columns>
</mx:DataGrid>
</mx:Panel>
</mx:Application>

Because the server is returning JSON as text, we can't use the <mx:XML> tag to get the data. So we use the <mx:HTTPService>> tag instead. It works a lot like the <mx:XML> tag. You give it a URL of the service, and then tell it the result format (i.e. text) and the ActionScript function to call when the HTTP service replies with the data.

In this case, I set the result function to the onJSONResult code that I specify in the <mx:Script> tag. This method takes out any whitespace and passes the JSON text onto the JSONDecoder object. It then sets the dataProvider on the <mx:DataGrid> control to the value returned from the JSONDecoder.

All of this is completely secure because ActionScript has no eval function. The JSONDecoder class is a simple state machine parser that builds objects from the text on the fly. In the worst case, it might just take a long time if the JSON text is too large.

Where to Go from Here

Flex is based on Flash, and Flash can talk to just about anything. It can talk directly to SOAP-based web services. It can even talk binary with protocols such as the Adobe Message Format (AMF).

If this is your first time using Flex, you might want to look into using Flex to build a Flash widget that you can post on your site to present data in a visually attractive way. To make sure that the Flash application is small enough to make for a fast download, be sure to make use of the Runtime Shared Library (RSL) functionality in the new Flash player. This allows you to cache big libraries (like the Flex library) in the client and then reuse them between different Flash applications.

Flex and Java are a strong team. Java provides excellent backend support on the server. And Flex along with ActionScript 3, provide a common cross-platform GUI layer that is easy to write and easy to adopt.


2009. 12. 12. 21:24

Changing the Flex ProgressBar from red -> green





Lets put a little pizazz in the Flex download ProgressBar. Really, going from, say, 0 -> 100 is great and all but maybe you need more. Like how about changing colors as it gets closer to completion?

view source

Now that’s more like it.

The meat and potatoes of this is in the following two methods:

1
2
3
4
5
6
7
8
9
10
http://polygeek.com/813_flex_changing-the-flex-progressbar-from-red-green
2009. 12. 11. 18:15

Creating full-screen Flex applications





Here is a quick post on using Flash Player 9’s Full-Screen Mode in Flex. I’ve seen this appear a few times in the bugbase and on lists, but here is some simple code to let you toggle between “full screen mode” and “normal mode” in a Flex application. Note that in this example I’m listening for the applicationComplete event in the main <mx:Application /> tag instead of the creationComplete event. The applicationComplete tag is called slightly after the creationComplete event, after the Application has been completely initialized.

If you try and access the Application.application.stage property from the creationComplete event, you’ll get a run-time error (RTE) saying the following:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at main/init()
at main/___main_Application1_creationComplete()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()
at mx.core::UIComponent/set initialized()
at mx.managers::LayoutManager/doPhasedInstantiation()
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/callLaterDispatcher2()
at mx.core::UIComponent/callLaterDispatcher()

The example below is pretty bare with just a few Label controls and a Button control, but it should have enough of the required code to give you a push in the right direction.

Full code after the jump.

You must have version 9,0,28,0 or greater of Flash Player installed to use full-screen mode. Download the latest version of Adobe Flash Player.

View MXML

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/07/creating-full-screen-flex-applications/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init(event)">

    <mx:Script>
        <![CDATA[
            import flash.display.StageDisplayState;

            private function init(evt:Event):void {
                /* Set up full screen handler. */
                Application.application.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler);
                dispState = Application.application.stage.displayState;
            }

            private function fullScreenHandler(evt:FullScreenEvent):void {
                dispState = Application.application.stage.displayState + " (fullScreen=" + evt.fullScreen.toString() + ")";
                if (evt.fullScreen) {
                    /* Do something specific here if we switched to full screen mode. */
                } else {
                    /* Do something specific here if we switched to normal mode. */
                }
            }

            private function toggleFullScreen():void {
                try {
                    switch (Application.application.stage.displayState) {
                        case StageDisplayState.FULL_SCREEN:
                            /* If already in full screen mode, switch to normal mode. */
                            Application.application.stage.displayState = StageDisplayState.NORMAL;
                            break;
                        default:
                            /* If not in full screen mode, switch to full screen mode. */
                            Application.application.stage.displayState = StageDisplayState.FULL_SCREEN;
                            break;
                    }
                } catch (err:SecurityError) {
                    // ignore
                }
            }
        ]]>
    </mx:Script>

    <mx:String id="dispState" />

    <mx:Label text="width={Application.application.width}" />
    <mx:Label text="height={Application.application.height}" />
    <mx:Label text="displayState={dispState}" />

    <mx:Button label="Toggle fullscreen" click="toggleFullScreen()" />

</mx:Application>

View source is enabled in the following example.

For more information on Full Screen Mode in Flash Player 9 (ActionScript 2.0 and ActionScript 3.0) check out the following article on the Adobe Developer Center: “Exploring full-screen mode in Flash Player 9″.

I *knew* I would have forgotten something. The real trick to using FullScreen support is to enable it in the JavaScript embed code, or <object /> and <embed /> tags… So, in your HTML wrapper, add the following property:

AC_FL_RunContent(
    "src", "main",
    "width", "100%",
    "height", "100%",
    "align", "middle",
    "id", "main",
    "quality", "high",
    "bgcolor", "#869ca7",
    "name", "main",
    "allowScriptAccess","sameDomain",
    "type", "application/x-shockwave-flash",
    "pluginspage", "http://www.adobe.com/go/getflashplayer",
    "allowFullScreen", "true"
);

Or, if you are using <object /> and <embed /> tags, you can use the following syntax instead:

<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
        id="main" width="100%" height="100%"
        codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
        <param name="movie" value="main.swf" />
        <param name="quality" value="high" />
        <param name="bgcolor" value="#869ca7" />
        <param name="allowScriptAccess" value="sameDomain" />
        <param name="allowFullScreen" value="true" />

    <embed src="main.swf" quality="high" bgcolor="#869ca7"
        width="100%" height="100%" name="main" align="middle"
        play="true"
        loop="false"
        quality="high"
        allowScriptAccess="sameDomain"
        allowFullScreen="true"
        type="application/x-shockwave-flash"
        pluginspage="http://www.adobe.com/go/getflashplayer">
    </embed>

</object>

Also, I just learnt from my co-worker Raghu’s blog (“FLEXing My Muscle” and his “Error on adding FullScreenListener in creationComplete handler” post) that you can use the SystemManager class instead of all my references to Application.application. Thanks Raghu!

<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2007/08/07/creating-full-screen-flex-applications/ -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" applicationComplete="init()">

    <mx:Script>
        <![CDATA[
            import flash.display.StageDisplayState;
            import mx.managers.SystemManager;

            private function init():void {
                /* Set up full screen handler. */
                systemManager.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler);
                dispState = systemManager.stage.displayState;
            }

            private function fullScreenHandler(evt:FullScreenEvent):void {
                dispState = systemManager.stage.displayState + " (fullScreen=" + evt.fullScreen.toString() + ")";
                if (evt.fullScreen) {
                    /* Do something specific here if we switched to full screen mode. */
                } else {
                    /* Do something specific here if we switched to normal mode. */
                }
            }

            private function toggleFullScreen():void {
                try {
                    switch (systemManager.stage.displayState) {
                        case StageDisplayState.FULL_SCREEN:
                            /* If already in full screen mode, switch to normal mode. */
                            systemManager.stage.displayState = StageDisplayState.NORMAL;
                            break;
                        default:
                            /* If not in full screen mode, switch to full screen mode. */
                            systemManager.stage.displayState = StageDisplayState.FULL_SCREEN;
                            break;
                    }
                } catch (err:SecurityError) {
                    // ignore
                }
            }
        ]]>
    </mx:Script>

    <mx:String id="dispState" />

    <mx:Label text="width={Application.application.width}" />
    <mx:Label text="height={Application.application.height}" />
    <mx:Label text="displayState={dispState}" />

    <mx:Button label="Toggle fullscreen" click="toggleFullScreen()" />

</mx:Application>
2009. 12. 10. 16:17

Using the Application.application.parameters





The parameters property of the Application object points to a dynamic object that stores parameters as name-value pairs. You can access variables on the parameters object by specifying parameters.variable_name.

The following example defines the myName and myHometown parameters and binds them to the text of Label controls:

<?xml version="1.0"?>
<!-- wrapper/ApplicationParameters.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="initVars()">
  <mx:Script><![CDATA[
     // Declare bindable properties in Application scope.
     [Bindable]
     public var myName:String;
     [Bindable]
     public var myHometown:String;
     
     // Assign values to new properties.
     private function initVars():void {
        myName = Application.application.parameters.myName;
        myHometown = Application.application.parameters.myHometown;
     }
  ]]></mx:Script>
  
  <mx:VBox>
  <mx:HBox>
     <mx:Label text="Name: "/>
     <mx:Label text="{myName}" fontWeight="bold"/>
  </mx:HBox>
  <mx:HBox>
     <mx:Label text="Hometown: "/>
     <mx:Label text="{myHometown}" fontWeight="bold"/>
  </mx:HBox>
  </mx:VBox>
</mx:Application>

When a user requests this application with the myName and myHometown parameters defined as flashVars variables, Flex displays their values in the Label controls.

To view all the flashVars properties, you can iterate over the parameters object, as the following example shows:

<?xml version="1.0"?>
<!-- wrapper/IterateOverApplicationParameters.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()">
  <mx:Script><![CDATA[
     private function init():void {
        for (var i:String in Application.application.parameters) {
           ta1.text += i + ":" + Application.application.parameters[i] + "\n";
        }
     }
  ]]></mx:Script>
  
  <mx:TextArea id="ta1" width="300" height="200"/>

</mx:Application>

Flex does not recompile the application if the request variables have changed. As a result, if you dynamically set the values of the flashVars properties or query string parameters, you do not force a recompilation.

Query string parameters must be URL encoded. The format of the string is a set of name-value pairs separated by an ampersand (&). You can escape special and nonprintable characters with a percent symbol (%) followed by a two-digit hexadecimal value. You can represent a single blank space using the plus sign (+).

The encoding for flashVars properties and query string parameters is the same as the page. Internet Explorer provides UTF-16-compliant strings on the Windows platform. Netscape sends a UTF-8-encoded string to Adobe Flash Player.

Most browsers support a flashVars String or query string up to 64 KB (65535 bytes) in length. They can include any number of name-value pairs.

2009. 12. 10. 14:31

Maths Functions including Random





The random function has many uses in Flash, generating basic random numbers, creating random movement, creating random colors and many others. The example above creates a random integer between -100 and 100 everytime you click the button. This tutorial will cover creating the example, and also how to incorporate the random function to achieve different results.

The basic random function is as follows:
Math.random();

This creates a random number between the values of 0.0 and 1.0. For example: 0.0105901374530933 or 0.872525005541986. Several other functions can now be used to change the number that is created for better use in your movie. These include:

Math.round();
 Math.ceil();
 Math.floor();

These Math functions all round a number so that it becomes an integer, or whole number. The Math.round(); function will round up or down the number or expression that is inside its brackets to the nearest whole number. The Math.ceil(); function will do the same, however it will always round up to the nearest whole number. The Math.floor(); function is the opposite of the Math.ceil(); , it will always round down to the closest whole number.

To incorporate these with the random function, you can do this:

Math.round(Math.random());

This expression will now create a random number between 0.0 and 1.0, and then round it up to the closest whole number. So in this case, the number created will always equal either 0 or 1. This expression is useful for creating a 50% chance of an event occuring, ie flipping a coin. or for use with booleans (true/false statements).

To create a random number between the values of, say 0 and 10, you could do this:

Math.round(Math.random()*10);

The *10 multiplies your random number by 10, then it is rounded by the Math.round function to an integer. To create a random number between 1 and 10, you could do this:

Math.ceil(Math.random()*10);

This way the random number is always rounded up, and cannot equal 0. Another procedure is to create random numbers between two numbers other than 0 and something else. To create a random number between 5 and 20, do this:

Math.round(Math.random()*15)+5;

Or in other words, to create a random number between the values x and y:

Math.round(Math.random()*(y-x))+x;

This will hold true for all values of x and y, ie they can be negative numbers as well as positive.

To make the example above, first create a new button, and place an instance of it onto the main stage. Create a new Dynamic text box, and give it the variable name of "display". That's the creation out of the way, and we can now do the scripting.

Select your button, and then open the actions window. You can either manually insert the following code, using the dropdown menus, or just copy and paste for now. Insert the code:

on (release) {
 display = Math.round (Math.random ()*200)-100;
 }

And that's it! Now test your movie and give it a try out. You'll notice that the values in the code follow the pattern set by the general formula ie if x = -100, and y =100, then y-x=200 and +x = -100.

This can have many different applications within flash. For example, to have a movieclip appear in random positions on the screen between the values of 0 and 200 you could have the following. Note: movieclip instance is called "bob".

bob._x = Math.round(Math.random()*200);
 bob._y = Math.round(Math.random()*200);

Or to set the size of a movieclip randomly (between 0 and 100):

bob._width = Math.round(Math.random()*100);
 bob._height = Math.round(Math.random()*100);

Or to choose a random movieclip to load, say if our movieclips have a linkage name of "bob1", "bob2" and we have 5 of them:

i = Math.ceil(Math.random()*5);
 attachmovie("bob"+i, "fred"+i, 1);

So that would attach a random movie, say "bob3", into level 1 and then give it an instance name of "fred3".

Well, that's the basics of using the random function in Flash 5. Hopefully now you will be able to incorporate this into your movies to produce some even more amazing flash work. =)

2009. 12. 10. 12:53

[Flex 3.3] DataGrid 에서 필요없는 스크롤바 없애는 방법




DataGrid 에 3 row 의 데이터를 넣고 rowCount="3" fontSize="12" 이렇게 셋팅하고 화면을 보면

<mx:DataGrid id="dg" dataProvider="{CIS}" width="296" rowCount="3" fontSize="12">
...








이렇게 원하지않는 세로스크롤바가 생깁니다.
폰트사이즈의 변경으로 row의 높이가 변경되면서 전체적인 높이가 데이터 사이즈에 맞게 변경되어야 하지만 위 그림처럼 스크롤바가 생깁니다. 
스크롤 해봐도 그 아래에는 물론 데이터도 없습니다.

이럴땐 verticalScrollPolicy="off" 을 사용하면

<mx:DataGrid id="dg" dataProvider="{CIS}" width="296" rowCount="3" fontSize="12" verticalScrollPolicy="off">
...








위 그림처럼 스크롤바가 없어집니다. 그러나 이경우 마지막 3번째 row 의 높이가 다른 row의 높이보다 낮습니다.

정확히 row 의 높이(header 높이 제외)가 같게 하기 위해선

  • headerHeight 의 높이 지정
  • headerWordWrap 값 true 로 설정

위 두가지 방법 중 하나만 사용해도 각 row 의 높이를 같게 할 수 있습니다.

2009. 12. 10. 12:31

Set the selected item for a comboBox or dataGrid




 

BSince the Flex 1.5 list-based controls do not support a "selectedItem" method, if you want to programatically set the control to a given value, you must loop over the items in the dataGrid, find a match, then set the selectedIndex.

The sample below does that for a comboBox and a dataGrid, plus shows setting vPosition to scroll the selection into view on the dataGrid.  It also has a simple labelFunction to build a label for the combo box.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" horizontalAlign="left"
  initialize="initApp()">
<mx:Script><![CDATA[
 private var gaDP1:Array;
 
 private function initApp():Void
 {
  gaDP1 = [ {label:"A", data:0},
     {label:"B", data:1},
     {label:"C", data:2},
     {label:"D", data:3},
     {label:"E", data:4},
     {label:"F", data:5},
     {label:"G", data:6},
     {label:"H", data:7},
     {label:"I", data:8},
     {label:"J", data:9}];  //build the dataProvider
 }
 
 //runs on click of button
 private function setInitialItem():Boolean
 {
  var aDP:Array = mx.utils.ArrayUtil.toArray(cbo1.dataProvider);
  var sDataValueInit:String = tiInitialData.text;
  var sDataValueCur:String;
  for ( var i:Number=0; i<aDP.length; i++ )  {  //loop over the items in the dataProvider
   sDataValueCur = aDP[i].data;  //get the current item.data value
   if ( sDataValueCur == sDataValueInit )  {  //compare desired value to current item.data value
    cbo1.selectedIndex = i;  //set the seletedIndex of the combo box
    dg1.selectedIndex = i;  //set the seletedIndex of the dataGrid
    dg1.vPosition = dg1.selectedIndex;  //scroll the dtagrid so the selected item is visible
    return true;
   }
  }//for ( var i:Number=0;....
  return false;
 }
 
 //example of labelFunction.  Creates a label out of both properties
 private function lfCB1(oItem:Object):String
 {
  return oItem.label + "  ( data:" + oItem.data + ")";
 }
]]></mx:Script>
   <mx:HBox>
  <mx:Label text="Initial Data Value (0-9)" />
  <mx:TextInput id="tiInitialData" />
  <mx:Button label="Set Item" click="setInitialItem()"/>
 

    <mx:ComboBox id="cbo1" dataProvider="{gaDP1}" width="150" labelFunction="lfCB1" />
  <mx:DataGrid id="dg1"  dataProvider="{gaDP1}" rowCount="4">
     <mx:columns>
        <mx:Array>
           <mx:DataGridColumn headerText="Label" columnName="label" />
           <mx:DataGridColumn headerText="Data" columnName="data" />
           </mx:Array>
        </mx:columns>
     </mx:DataGrid>
  </mx:HBox>
</mx:Application>



<?xml version="1.0"?>
<!-- dpcontrols/ComboBoxEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
   <mx:Script>
      <![CDATA[
         import flash.events.Event;
         import mx.events.DropdownEvent;

         // Display the type of event for open and close events.
         private function dropEvt(event:DropdownEvent):void {
            forChange.text+=event.type + "\n";
         }

         // Display a selected item's label field and index for change events.
         private function changeEvt(event:Event):void {
            forChange.text+=event.currentTarget.selectedItem.label + " " + 
               event.currentTarget.selectedIndex + "\n";
         }
      ]]>
   </mx:Script>

   <mx:ComboBox open="dropEvt(event)" close="dropEvt(event)"
         change="changeEvt(event)" > 
      <mx:ArrayCollection>
         <mx:Object label="AL" data="Montgomery"/>
         <mx:Object label="AK" data="Juneau"/>
         <mx:Object label="AR" data="Little Rock"/>
      </mx:ArrayCollection>
   </mx:ComboBox>
   <mx:TextArea id="forChange" width="150" height="100%"/>
</mx:Application>

The executing SWF file for the previous example is shown below:

If you populate the ComboBox control with an Array of Strings, the currentTarget.selectedItem field contains a String. If you populate it with an Array of Objects, the currentTarget.selectedItem

2009. 12. 7. 10:40

YouTube flv 소스 가져오기




http://dennisjaamann.com/blog/?p=70

Youtube video in AS3 FLVPlayback

Lately,
I’ve been busy trying to get youtube movies to play in the standard FLVPlayback component.

Getting this to work was really a pain in the butt now and then, especially because while I was working on this,
youtube changed some stuff on their side undoing all my previous work. But hey, stuff happens!
In the end perseverance and a lot of patience finally resulted in a working solution.

I will break up the solution into several pieces, describing the steps that need to be taken in order for this to work.

1) We need to get the video (.flv) from the youtube server.

To achieve this, one must of course understand how to get this video.
To start off, just navigate to a youtube movie. e.g. http://www.youtube.com/watch?v=vE_WqdKbTvY , then right-click anywhere in page and watch the page source code.

In the source code, search for the string “swfArgs”, which will look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var swfArgs = {
"q": "top%20gear%20carrera%20gt",
"fexp": "903500,900130", 
"invideo": true, 
"sourceid": "ys",
"video_id":"vE_WqdKbTvY", 
"l": 478,
"fmt_map": "18/512000/9/0/115,34/0/9/0/115,5/0/7/0/0", 
"sk": "PbB4AIyvqpbLl0DYyCX5rpmXcQe-FEcZC", 
"is_doubleclick_tracked": "1", 
"usef": 0,
"t": "vjVQa1PpcFO6TnxVA4_nkqbqKN-z4CoWJgWn2Pfu77I=", 
"hl": "en", 
"plid": "AARoEenKN8A9FYLn", 
"vq": null, "ad_module": "http://s.ytimg.com/yt/swf/ad-vfl91517.swf", 
"cr": "NL", 
"tk": "j7SixOLxSJ1xxBIwWubnN9sXiu7hrejTmRv4ruMx4N3OaeyhN0xImQ=="};

As you can see this is an object, containing data about the swf and thus the .flv played at the youtube html page.
The video_id is the identifier of the movie and t is a token set by youtube that enables you to view / download the video.
This token expires after a given period of time, so I can’t place a permanent download link for the flv file here.

So now that we have the parameters of the video we need to fill them in as follows into a fixed url, used by youtube to retreive the flv video:
http://www.youtube.com/get_video.php?video_id=[id]&t=[t]
In our case:
http://www.youtube.com/get_video.php?video_id=vE_WqdKbTvY&t=vjVQa1PpcFO6TnxVA4_nkqbqKN-z4CoWJgWn2Pfu77I=
When navigating to this url with your browser, the video will start downloading

Don’t bother trying to open this last link, because as stated before, the token will probably have expired by the time you read this.
(Also the token is linked to the IP that first requested it, which in this case would be mine. More about this later)
If you would like to test if and how this works, just follow all the steps described above and see for yourself.
Pretty cool huh?

Now that we know how to get the .flv video of any youtube movie, we need to find a way to automatically do this, without the need to go through all the steps again.
We will use a php proxy script that eliminates all sandbox issues, accepts any youtube url and then returns the physical video (.flv) as if it were present on our own server.
However, this script will be a mere redirect to the location of the video on youtube servers, the file will not be physically downloaded by your server.

To create a script like this, I did some searching and quickly stumbled upon a script I found here.
This worked fine at first, but as I was saying youtube changed some things server side along the way.
That’s why i needed to search for a solution and needed to modify the script in order to getting it to work again.

The problem was caused because youtube changed the token idea.
A token is now linked to an IP address, meaning that the video can only be downloaded by the IP address that first requested the token.
This is a problem when trying to do this in-browser, where the browser is on the localhost, and the script is on a server and thus causing an IP mismatch. The result is that the file cannot be accessed.
After alot of searching around the final solution is to retreive the headers from the youtube download url and extracting the location of the flv that is embedded.

The result for the php proxy script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
    $id = trim($_REQUEST['id']);
 
    $url = "http://www.youtube.com/watch?v=" . $id;
 
    $url = $url . "&fmt=18"; //Gets the movie in High Quality, uncomment this line to get it in normal quality
 
    $ch = curl_init();
 
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HEADER, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 
    $info = curl_exec($ch);
 
    if (!preg_match('#var swfArgs = (\{.*?\})#is', $info, $matches))
    {
        echo "Check the YouTube URL : {$url} <br/>\n";
        die("Couldnt detect swfArgs");
    }
 
    if (function_exists(json_decode)) # >= PHP 5.2.0
    {
	$swfArgs = json_decode($matches[1]);
        $video_id = $swfArgs->video_id;
        $t = $swfArgs->t;
    }
    else
    {
        preg_match('#"video_id":.*?"(.*?)"#is', $matches[1], $submatches);
        $video_id = $submatches[1];
 
        preg_match('#"t":.*?"(.*?)"#is', $matches[1], $submatches);
        $t = $submatches[1];
    }
 
    curl_close($ch);
 
    $fullPath = "http://www.youtube.com/get_video.php?video_id=" . $video_id . "&t=" . $t; // construct the path to retreive the video from
 
    $headers = get_headers($fullPath); // get all headers from the url
 
    foreach($headers as $header){ //search the headers for the location url of youtube video
	if(preg_match("/Location:/i",$header)){
	    $location = $header;			  
	}
    }
 
    header($location); // go to the location specified in the header and get the video
?>

An example of correct usage:

Navigate to http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=[videoID],
where the videoID is the id from the youtube movie http://www.youtube.com/watch?v=vE_WqdKbTvY
In this case: http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=vE_WqdKbTvY
When navigating to the url above, you will notice that the script will redirect you to the physical location of the .flv file.This will start the download prompt.

Isn’t this exactly what we need? :)

2) Workaround for FLVPlayback

When we take the url retreived above and try to play it in the standard FLVPlayback component as follows:

1
2
3
4
	var videoPlayer:FLVPlayback = new FLVPlayback();
        addChild(videoPlayer);
	videoPlayer.source = "http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=vE_WqdKbTvY";
	videoPlayer.play();

The video doesn’t play and we get the following error:
VideoError: 1005: Invalid xml: URL: “http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=vE_WqdKbTvY&FLVPlaybackVersion=2.1″ No root node found; if url is for an flv it must have .flv extension and take no parameters
at fl.video::SMILManager/http://www.adobe.com/2007/flash/flvplayback/internal::xmlLoadEventHandler()
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at flash.net::URLLoader/onComplete()

Which is kind of a suprise, because when we open the source url in our browser there is clearly an .flv file there.

However, when analyzing the error message we can clearly see the problem. The key part here is:
“if url is for an flv it must have .flv extension and take no parameters”
When taking a look at our url http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=vE_WqdKbTvY,
it is obvious that it doesn’t end on .flv and that our url accepts parameters.

This behaviour is caused by a few lines of code in the NCManager class used by the FLVPlayback component.
There, the check is done whether the url ends on .flv and that the url does not accept parameters.

This leaves us 2 options:
- Extend the NCManager, overwrite this behaviour and make the FLVPlayback use this custom class
- Find a way to give the NCManager a correctly formatted url, so that it can stop nagging

I prefer the second option because it leaves the NCManager unmodified and hereby we can eliminate any unwanted behaviour.
Also, since I have a little php experience, I quickly realized that this had the funky smell of url rewriting.
With url rewriting you can take any url and format it to the format required which is exactly what we need here…

So we need to change the original url
http://www.dennisjaamann.com/demo/youtubeFLVPlayback/php/getYoutubeFLV.php?id=vE_WqdKbTvY
to
http://www.dennisjaamann.com/demo/youtubeFLVPlayback/videos/vE_WqdKbTvY.flv

This can be achieved by adding a .htaccess file to your project folder on the web server.
The code below is also included in the source files at the bottom of this post. But please note, not all operating systems show a .htaccess file.
This is because that it sometimes is a hidden file type.

Here’s the code for that:

1
2
3
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^videos/([^/]+).flv php/getYoutubeFLV.php?id=$1 [NC]

And that’s all folks!
When we now execute our code again with the modified url, the NCManager has stopped nagging and the videoplayer plays the wanted video.

1
2
3
4
	var videoPlayer:FLVPlayback = new FLVPlayback();
        addChild(videoPlayer);
	videoPlayer.source = "http://www.dennisjaamann.com/demo/youtubeFLVPlayback/videos/vE_WqdKbTvY.flv";
	videoPlayer.play();

This workaround took like a minute or so to be succesful, leaves the the NCManager unchanged and does the trick.
That’s why I’ve chosen this solution because it is simple and elegant.

Read more about basic url rewriting here

3) Create the player.

All that is left now is to create our application. I have prepared an example in flex (sdk 3.3)

This is the result:

View the full example with source here
Or download the example source files here: youtubeFLVPlayback (851)

Tags: , , , , ,

2009. 11. 20. 09:36

[Flex] comboBox를 이용한 필터링




<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="simpletestCat.send();simpletestFood.send()"  layout="horizontal">

<mx:Script>
<![CDATA[
  import mx.controls.dataGridClasses.DataGridColumn;
  import mx.collections.ArrayCollection;

  [Bindable]
  private var categoryList:ArrayCollection;
  [Bindable]
  private var foodList:ArrayCollection;
 
  private function filterByCategory(event:Event):void{
   if((event.target as ComboBox).selectedIndex == 0){
    foodList.filterFunction = null;
   }else{
    foodList.filterFunction = catFilter;    
   }
   
   foodList.refresh();
   foodListBox.selectedIndex =0
  }
 
  private function catFilter(item:Object):Boolean{
   return item.category_name == categorySelect.selectedItem.category_name;
  }

]]>
</mx:Script>

<mx:HTTPService id="simpletestCat"
url="assets\categorylist.xml"
result="categoryList=simpletestCat.lastResult.list.category;categoryList.addItemAt('All', 0);categorySelect.selectedIndex=0"/>
<mx:HTTPService id="simpletestFood"
url="assets\foodlist.xml"
result="foodList=simpletestFood.lastResult.list.food"/>

<mx:ComboBox id="categorySelect" change="filterByCategory(event)"
dataProvider="{categoryList}"
labelField="category_name"/>
<mx:ComboBox id="foodListBox"
dataProvider="{foodList}"
labelField="product_name"
width="200"/>

</mx:Application>

2009. 11. 19. 19:15

VideoDisplay 컨트롤 시작해보기




나는 이전에 VideoDisplay 컨트롤로 간단한 예제를 생성해서 플래시 비디오(FLV)가 로딩할때 이벤트 순서의

이해를 돕도록 만들었습니다.

 

다음 예제는 VideoDisplay 컨트롤을 만들고,

디버깅 DataGrid 안에 각각 FLV의 이벤트 , 비디오 상태 , 플레이헤드 타임 , 총 재생시간을 표시합니다:

 

 

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" backgroundColor="white" creationComplete="init();">

 

    <mx:Script>

        <![CDATA[

            import mx.collections.ArrayCollection;

            import mx.events.CuePointEvent;

            import mx.events.VideoEvent;

 

            [Bindable]

            private var arrColl:ArrayCollection;

 

            [Bindable]

            private var FLV_URL:String = "http://www.helpexamples.com/flash/video/clouds.flv";

 

            /**

             * Initialize the ArrayCollection object.

             */

            private function init():void {

                arrColl = new ArrayCollection();

            }

 

            private function doVideoEvent(evt:VideoEvent):void {

                doAddItem({type:evt.type});

            }

 

            private function doCuePointEvent(evt:CuePointEvent):void {

                doAddItem({type:evt.type});

            }

 

            private function doProgressEvent(evt:ProgressEvent):void {

                doAddItem({type:evt.type});

            }

 

            /**

             * Add the item to the ArrayCollection instance, revalidate the DataGrid control, and scroll to the last item in the DataGrid.

             */

            private function doAddItem(obj:Object):void {

                arrColl.addItem({type:obj.type, state:videoDisplay.state, playheadTime:videoDisplay.playheadTime, totalTime:videoDisplay.totalTime});

                dataGrid.validateNow();

                dataGrid.selectedIndex = arrColl.length;

                dataGrid.scrollToIndex(arrColl.length);

            }

        ]]>

    </mx:Script>

 

    <mx:VideoDisplay id="videoDisplay" source="{FLV_URL}" autoPlay="false" autoRewind="false"

            ready="doVideoEvent(event);"

            rewind="doVideoEvent(event);"

            playheadUpdate="doVideoEvent(event);"

            close="doVideoEvent(event);"

            complete="doVideoEvent(event);"

            progress="doProgressEvent(event);" />

 

    <mx:HBox>

        <mx:Button label="play()" click="videoDisplay.play();" />

        <mx:Button label="pause()" click="videoDisplay.pause();" />

        <mx:Button label="stop()" click="videoDisplay.stop();" />

    </mx:HBox>

 

    <mx:DataGrid id="dataGrid" dataProvider="{arrColl}" width="320" rowCount="5">

        <mx:columns>

            <mx:DataGridColumn id="typeCol" dataField="type" headerText="Evt. type" />

            <mx:DataGridColumn id="stateCol" dataField="state" />

            <mx:DataGridColumn id="playheadTimeCol" dataField="playheadTime" textAlign="right" />

            <mx:DataGridColumn id="totalTimeCol" dataField="totalTime" textAlign="right" />

        </mx:columns>

    </mx:DataGrid>

 

</mx:Application>

 

* 이 문서의 권한은 http://blog.flexexamples.com 에 있음을 밝힘니다. 2차 가공물의 권한은 저에게 있습니다.