Tuesday, December 20, 2011

Aligning Text in Spark Label

I have been asked this question quite a few times, so I thought I'd place this in here too... :)

So how does one align text in a Spark Label.

There are 2 styles one needs to set based on how the alignment is required to be. "textAlign" and "verticalAlign".

textAlign
This sets the horizontal alignment of the text in the Label. This can be set to one of the 3 values viz., 
"start", "center", "end".
By default the textAlign is set to "start" in a Spark Label.

This also depends on another style in Label called, "direction". The "direction" style sets the direction of the text in the Label,
"ltr" (Left To Right) as in regular English
"rtl" (Right To Left) as in Arabic/Urdu

When the direction is set to "ltr", "start" indicates the left end of the label and "end" indicates the right end of the label. It is vice versa in case the direction is set to "rtl"

verticalAlign
The "verticalAlign" style aligns the text vertically in the Label. This can be set to one of the 5 values viz,
"top", "middle", "bottom", "justify", "inherit"

The default value for a Spark Label is "top".

Saturday, November 19, 2011

itemEditEnd event mx Datagrid

Some salient points that I came across when working with itemEditEnd event in the mx:DataGrid. Thought I'd share.

  1. In case of editable datagrids, we can do some updation, if required before the completion of the edit by listening to the itemEditEnd event in the DataGrid.
  2. mx:DataGrid also listens to the same event and does some processing before destroying the itemEditor instance for the row.
  3. Flex adds the event listener with a priority of -50 in the DataGrid. The default priority when we add the event listener is 0. Hence, our code will be executed first always.
  4. To override this, we can set the event listener priority less than -50. Doing so will make our code to be executed after the Flex inbuilt code.
  5. We can also add multiple event listeners for the same event with varying priorities, to enable code synchronization.
  6. itemEditEvent does not store the old value and the new value, so we need to pick that ourselves to do some processing on them.
  7. It is also advisable to use the data from the itemRenderer as the old value and that from the itemEditor instance as the new value. Using this from values stored outside may have consequences, we might not like.
So, there it is. Hope this helps someone.


Thursday, November 17, 2011

Setting Excel Column Width with AS3XLS

In my previous posts we talked about exporting to excel and formatting using AS3XLS. Here we go furthur and add a feature into AS3XLS. We'll extend it to support custom column width. Let's see how we can achieve that. Onward ho!!!

Since AS3XLS does not give the capability of adding custom column width, we'll need to extend the saveToByteArray method of the AS3XLS. What I did was to create a new function in my code and passed the Sheet and an array of the custom column widths that I collected from the user. I have placed the code below. Hope it helps.


private function saveToByteArray(s:Sheet, columnWidths:Array):ByteArray 
{
        ....... same code as in the AS3XLS saveToByteArray()
        // Custom code starts
for (var i:uint = 0; i < columnWidths.length; i++) 
{
var colwidth:Record = new Record(Type.COLINFO);
colwidth.data.writeShort(i); // start index 
colwidth.data.writeShort(i); // end index
colwidth.data.writeShort(columnWidths[i] * 256);
br.writeTag(colwidth);
}

for(var r:uint = 0; r < s.rows; r++) 
{
for(var c:uint = 0; c < s.cols; c++) 
{
var value:* = s.getCell(r, c).value;
var cell:Record = new Record(1);
cell.data.writeShort(r);
cell.data.writeShort(c);

// Check for value types and add to the cell bytes as in AS3XLS and finally write it in the    BiffRecord
}
}
// Custom code ends
// Finally, the closing EOF record
var eof:Record = new Record(Type.EOF);
br.writeTag(eof);

br.stream.position = 0;
return br.stream;
}

Tuesday, November 15, 2011

Passing data between datagrid itemRenderers


Recently I had to build a component where I had to communicate between item renderers of 2 columns in a datagrid to keep them updated. What made the task more worthwhile was that the item renderers were combo boxes, the data providers for which came from an external source and not the data provider for the datagrid. So, here's how I went on about it. 


1. The datagrid dataprovider was set and the dataField for each of the column item renderers were added.
2. In the first item renderer, set the dataprovider for the combobox and add an event listener for the change event. In the event listener formulate a new event that  sends the itemIndex of the renderer and the selected data.
3. On the creation complete of the second itemrenderer add the event listener for the above event on the parentDocument.
4. In the handler function, if the itemIndex matches then based on the selected data, change the display.


And lo and behold!! We are all set.

Sunday, October 23, 2011

Exporting to excel with AS3XLS

Straight to the point. Code below shows how to do it. I guess I have added enough comments to explain the flow.


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
               xmlns:s="library://ns.adobe.com/flex/spark"
               xmlns:mx="library://ns.adobe.com/flex/mx"
               width="100%" height="100%" initialize="init()">
    <fx:Script>
        <![CDATA[
import com.as3xls.biff.BIFFVersion;
import com.as3xls.biff.BIFFWriter;
import com.as3xls.biff.Record;
import com.as3xls.xls.ExcelFile;
import com.as3xls.xls.Formatter;
import com.as3xls.xls.Sheet;
import com.as3xls.xls.Type;

import mx.collections.ArrayCollection;
import mx.collections.ListCollectionView;
import mx.core.UIComponent;

import utils.ExcelExportUtil;

            private function init():void
   {
                var data:Array = new Array();
                for(var r:uint = 0; r < 50; r++)
{
                    data.push({col1:"Col1: " + r, col2:"Col2: " + r, col3:(r+1), col4:new Date(), col5:"Col5: " + r});
                }
                dataGrid.dataProvider = new ArrayCollection(data);
            }

    private function export():void
    {

var s:Sheet = new Sheet();
s.resize(datagrid.dataprovider.length, datagrid.columns.length);
                        var row:*;

for(var r:uint = 0; r < datagrid.dataprovider.length; r++)
{
for(var c:uint = 0; c < s.cols; c++)
{
row = datagrid.dataprovider.getItemAt(r);
rowValue = row[c];
s.setCell(r, c, (rowValue != null ? rowValue : ""));
}
}

var xls:ExcelFile = new ExcelFile();
xls.sheets.addItem(s);
var bytes:ByteArray = xls.saveToByteArray();

var fr:FileReference = new FileReference();
fr.save(bytes, "ExcelFile.xls");

    }
        ]]>
    </fx:Script>
    <s:layout>
        <s:VerticalLayout/>
    </s:layout>
    <s:Button label="Export" click="export()"/>
    <mx:DataGrid id="dataGrid" width="100%" height="100%" />
</s:Application>

Friday, October 21, 2011

Closing PopUp on Esc Press

A nice to have feature that I was implementing, brought me to this. As it turns out, this actually is very easy to implement. Code below.

The Application File


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
  xmlns:s="library://ns.adobe.com/flex/spark"
  xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600"
   >

<fx:Script>
<![CDATA[
import components.TestPopUp;

import mx.core.FlexGlobals;
import mx.managers.PopUpManager;

private function addPopUp(event:MouseEvent):void
{
var popup:TestPopUp = new TestPopUp();
PopUpManager.addPopUp(popup, FlexGlobals.topLevelApplication as DisplayObject, true);
PopUpManager.centerPopUp(popup);
}

]]>
</fx:Script>
<s:Button id="addPopBtn" label="Add Pop Up" click="{this.addPopUp(event)}"/>
</s:Application>

Custom Pop Up

<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009" 
  xmlns:s="library://ns.adobe.com/flex/spark" 
  xmlns:mx="library://ns.adobe.com/flex/mx" 
  width="400" height="300" creationComplete="init()"
  close="onClose(event)">
<fx:Script>
<![CDATA[
import mx.events.CloseEvent;
import mx.managers.PopUpManager;
private function init():void
{
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
}
private function onKeyDown(event:KeyboardEvent):void
{
if(event.keyCode == Keyboard.ESCAPE)
{
PopUpManager.removePopUp(this);
}
}
private function onClose(event:CloseEvent):void
{
PopUpManager.removePopUp(this);
}
]]>
</fx:Script>
<s:Label text="Hi There. Press Esc to close me."/>
</s:TitleWindow>

Monday, October 17, 2011

Understanding Spark Skinning - Part 3

This is the third and final part of the 3 part series to understand Skinning in Spark.
PART 1 - Introduction to Skinning

Skinning a Button Component

In this part we'll take a simple Spark Button and see if we can do something interesting with it. So let us take a moment to figure out what we want to do with the button. What I am planning to do is to give my button a custom shape and change the colors. The code below just does that. We use the Spark Skin class and extend it to create our custom skin.
The final product looks something like this. 
Default

On Hover


I hope I have added enough comments.. :) 

<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/halo"
minWidth="40" minHeight="40">

        <!-- Add the HostComponent for the skin -->
<fx:Metadata>
[HostComponent("spark.components.Button")]
</fx:Metadata>

        <!-- Define the states for the component -->
<s:states>
<s:State name="up"/>
<s:State name="down"/>
<s:State name="over"/>
<s:State name="disabled"/>
</s:states>

        <!-- 
                 The Path tag allows to draw custom shapes. This currently draws a star.
                 With the filters we add the background for the button
                 This draws the default skin that will be used for all states
        -->
<s:Path data="M 50 0 L 70 30 H 100 L 80 60 L 100 100 L 50 80 L 0 100 L 20 60 L 0 30 H 30 L 50 0">
<s:filters>
<s:DropShadowFilter blurX="20" blurY="20" alpha="0.5" distance="11" angle="90"/>
</s:filters>
<s:stroke>
<s:LinearGradientStroke weight="1">
<s:GradientEntry color="0x0000FF" ratio=".25"/>
<s:GradientEntry color="0xFFFFFF"/>
</s:LinearGradientStroke>
</s:stroke>
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"/>
<s:GradientEntry color="0x0000FF"/>
</s:LinearGradient>
</s:fill>
</s:Path>


        <!-- 
                 The Path tag allows to draw custom shapes. This currently draws a star.
                 With the filters we add the background for the button
                 This draws a custom layout for the "over" state
        -->
<s:Path data="M 50 0 L 70 30 H 100 L 80 60 L 100 100 L 50 80 L 0 100 L 20 60 L 0 30 H 30 L 50 0" includeIn="over">
<s:stroke>
<s:LinearGradientStroke weight="1">
<s:GradientEntry color="0x0000FF" ratio=".25"/>
<s:GradientEntry color="0xFFFFFF"/>
</s:LinearGradientStroke>
</s:stroke>
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF"/>
<s:GradientEntry color="0x0000FF" ratio=".25"/>
</s:LinearGradient>
</s:fill>
</s:Path>


        <!--
                 The label is added to add the text for the button
        -->
<s:Label id="labelDisplay" horizontalCenter="0" verticalCenter="-5"/>

</s:SparkSkin>

Tuesday, September 27, 2011

Understanding Spark Skinning - Part 2


This is the second part of the 3 part series to understand Skinning in Spark.
PART 1 - Introduction to Skinning

Skin Class
The Skin Class is the class that defines the look and feel (logic, graphical elements, states etc)of the component class. The Skin Class has the following elements

  • Skin root tag (or a subclass)
  • Host Component metadata
  • State declarations
  • Skin Parts
  • Script Block to define the logic
  • Graphical Elements and children
Skin Root Tag
The Skin Class uses a root tag which defines the entry point of the class. The root tag may be or or a subset of the


Host Component
The HostComponent is the component that uses the skin. This metadata is optional but recommended. Specifying this metadata allows the skin class to gain a reference to the component instance that uses the skin. Also, if specified the skin class can check in compile time for the skin parts and the skin states defined in the Host Component. You can specify this as below


<Metadata>
      [HostComponent{"spark.components.Button"}]
</Metadata>


State Declarations
The skin needs to change its visual appearance based on the states of the component. The skin states define the appearance w.r.t the elements in the skin and their display state. Thus for each state of the host component a state is defined for the skin, where in the display is changed. Skin states are defined as below,

<s:states>
      <s:state name="up"/>
      <s:state name="down"/>
</s:states>


Skin Parts
Skin Parts are the components defined in the skin class and the host component. These are a great way of binding the component data into the skin. Thus the host declares the part and the appearance is defined by the skin. If declared in the host component the skin has to implement it. 
To declare a skin part in the host component the [SkinPart] metadata has to be used

[SkinPart(required=true)]
public var textLabel:Label;

The Skin Class defines a label as the textLabel part;

Note that the id of the label defined in the skin class matches that of the variable in the host component.

These are the basic stuff required for skinning. In the next part we'll use these to put together a skinning example.

Sunday, September 25, 2011

Understanding Spark Skinning - PART 1

Introduction to Skinning
In my previous post we saw the basic difference between skinning between Flex 3 (Halo) and Flex 4(Spark). Let us further delve into the world of Spark Skinning. I'll go through this in a 3 part series where we'll discuss the basics of skinning and put together an example.


An important thing to note before proceeding is that, while skinning spark components is that though it may look a bit difficult and time consuming, it is actually quite simple.

Skinning Contract
Skinning spark components starts with a Skinning Contract. The Skinning Contract between the skin class and the component class defines the set of rules that each class must follow in order to ensure communication between them.
The skinning class part of the contract tells that the Skin Class must do the following
  • Specify the host component
  • Declare the skin states
  • Define appearance of skin parts
  • Optionally bind data defined on the host component
The host component must
  • Identify skin states with metadata
  • Identify skin parts with metadata
  • Define data that is bound to the skin class
The compiler validates the HostComponent , SkinPart and SkinStates in the skin class. So, all the states and the skin parts that are there on the host component must be declared in the skin class.
A skin can be applied to a component only after a valid contract is established between the two.

Skinning - Flex 3 vs Flex 4

Skinning UI Components has largely been a necessity in the world of Web 2.0. Every application needs to look different and feel different. In such a scenario, Flex had brought the concept of skinning, that lent a fresh and different look to each component with the help of skin classes.

In Flex 3, the skin was tightly bound to the component. So, the entire look and feel was intertwined with the functionality of the component. However, in Flex 4 Adobe has made a refreshing change, separating functionality and display. The display aspects is moved from the component code to the skin class.

What it means for us is that in Halo components the look and feel of the component is directly connected to the methods of the component whereas, in spark components, the look and feel have been separated from the functional behaviour of the component. The impact this makes is that no matter how you skin the component in Flex 3, they'll always be similar in the way they look and feel. On the other hand in Flex 4, two components can be drastically different in the way they look and feel and yet have the same functionality.

The other beautiful thing that comes out of the separation is that developers and designers are no longer dependent on each other. The developer has the freedom to write the logic without worrying about the appearance and the designer can create the UI without worrying about the effects into the code logic. With Flash Catalyst the creation of UI has become even more simpler. As a direct result of this, the requirement changes that were previously so hard to accommodate due to monkey patching are done very simply in Flex 4.


Monday, September 19, 2011

Creating overlay in Flex

Sometimes we may need to create a modal window in a Flex Application. In such cases, we need to add an overlay to the application. The post below explains how to achieve the same.

/* The overlay component */
private var overlay:FlexSprite;

/* Create an overlay 
 * Create a new sprite with an alpha to make it translucent
 * Create a rectangle of the size of the system manager screen and fill the overlay with that
 * Add the overlay to the system manager.
 */
private function createOverlay():void
{
if(this.overlay == null)
{
this.overlay = new FlexSprite();
this.overlay.alpha = 0.5;
this.overlay.tabEnabled = false;
var s:Rectangle = this.systemManager.screen;
var g:Graphics = this.overlay.graphics;
g.clear();
g.beginFill(0xDDDDDD, 100);
g.drawRect(s.x, s.y, s.width, s.height);
g.endFill();
this.systemManager.addChild(this.overlay);
}
}

/* Remove the overlay */
private function removeOverlay():void
{
if(this.overlay != null)
{
this.systemManager.removeChild(this.overlay);
this.overlay = null;
}
}

As simple as that. Questions are welcome.

Saturday, September 17, 2011

Multi Data Converter


Multi Data Converter

Version 1.0


ABOUT

Multi Data Conveter is a data conversion utility designed to allow users to convert between various units of data. The application currently supports data conversion for units of "Distance", "Currency", "Weight" and "Temperature".

FEATURES
  • Free to download, install and distribute
  • Single click usage
  • Currency Converter tries to get the latest conversion rates
  • Get all conversions right on your desktop.

USAGE
  • Download the zip file by clicking on the download link
  • Extract the zip
  • Run the installer in the zip file
  • Select the default settings while installing
  • Run "Multi Data Converter" using one of the shortcuts on desktop or in the startup menu.
  • Select the converter that is to be used.
  • Enter the value to be converted
  • Select the units from and to which the value is to be converted .
  • Click on Go.


SCREEN SHOTS









Disclaimer

Multi Data Converter is designed with the intention to help users to convert data right from the desktop.

The utility is free for use by any individual or organization without restrictions. However the author, flexmycode.com and blogger.com are not responsible for any damage caused by the misuse of this tool.

Friday, September 9, 2011

Singleton Class in ActionScript

As in JAVA, ActionScript does not have a private constructor. So, the job of creating a singleton class is not really simple. However, we can create Singleton classes in ActionScript. Below is a simple class that does the trick.

package utils
{
public class SingletomExample
{
private static var instance:SingletomExample;
public function SingletomExample(enforcer:SingletonEnforcer)
{
if (!enforcer)
{
throw new Error("Cannot instantiate a Singleton class. Use getInstance() instead");
}
}
public static function getInstance():SingletomExample
{
if (!instance)
{
instance = new SingletomExample(new SingletonEnforcer());
}
return instance;
}
}
}

class SingletonEnforcer{}

And lo and behold, your Singleton class is here.

Some Explanation:
The code is pretty much self explanatory. A class "SingletonEnforcer" is added to the package. This is an internal class that no one can access outside the class. Using internal class this to enforce the Singleton makes it impossible to break the Singleton nature.

Hope this helps..

Monday, September 5, 2011

Adding a Scroller in Spark Component

Flex 3 components had scrollers in-built in the components that we used. However, that is not the case in Flex 4 (Spark). Scrollers are not usually required in applications, mainly because people do not like scrolling through the page. A saying goes like, "If there's a scroller to a component, probably the things behind the scroller are not that important".Which is why most applications today do not contain a lot of scrollable areas. The removal of in-built scrollers from the components thus added an edge to Flash applications by removing the overhead of the extra code that is mostly not used and thus reducing the overall size of the application.
However, there will be some cases in an application where we need to use the scroll feature. So how do we implement this in Flex 4. The code below explains the same,

<s:Application .........
>

<s:Scroller>
      <s:Group id="scrollGroup" .... >
            <!-- component UI here -->
      </s:Group>
</s:Application>

As simple as that. Add the required properties into the scroller (left, right, top etc...) and you can customize it. You can even skin the scroller separately to what you require.
-Cheers.  

Wednesday, August 31, 2011

Listening to Spark ComboBox Prompt Change

The spark ComboBox has a great feature of the prompt being editable by default. So how does one listen to the change of the text in the prompt.

One way of doing this is to listen to the change event fired by the ComboBox

<s:ComboBox id="comboBox" change="changeHandler(event)" />


private function changeHandler(event:IndexChangeEvent)
{
       //do something
}


The other way is to listen to the textChange of the prompt text

private function init():void
{
       comboBox.textInput.addEventListener(TextOperationEvent.CHANGE, textChangeHandler);
}


private function textChangeHandler(event:TextOperationEvent):void
{
       //Do Something
}

There. Hope someone finds use for this.

Monday, August 29, 2011

Full Screen in Flex 4

Flex provides a great way of setting web applications into full screen on the desktop. The following code snippet demonstrates the same.

public function toggleFullScreen(uiComponent:UIComponent):void
{
       if(uiComponent.stage.displayState == StageDisplayState.NORMAL)
              uiComponent.stage.displayState = StageDisplayState.FULL_SCREEN;
       else if (uiComponent.stage.displayState == StageDisplayState.FULL_SCREEN)
              uiComponent.stage.displayState = StageDisplayState.NORMAL;
}

The piece of code will set any component into the full screen mode, except the fact that it does not actually solve the purpose. It actually gets the whole application into full screen mode.
That is because setting the full screen property belongs to the Stage object. The flash runtime however has only one stage and all the components displayed refer to the same stage. [For more refer this]. This brings us to the problem. How do you get only the component to fullscreen. Fortunately, there's a simple way to achieve this. Take a look at the code below and I'll explain the nuances after that.

private var componentWidth:Number;
private var componentHeight:Number;
private var sourceComponent:UIComponent;


public function toggleComponentFullScreen(uiComponent:UIComponent):void
{
var stage:Stage = FlexGlobals.topLevelApplication.stage;

if(uiComponent != null && stage.displayState == StageDisplayState.NORMAL)
{
this.componentWidth = uiComponent.width;
this.componentHeight = uiComponent.height;
this.sourceComponent = uiComponent;

this.sourceComponent.width = stage.stageWidth;
this.sourceComponent.height = stage.stageHeight;

var p:Point = new Point(0,0);
p=view.localToGlobal(p);

var sourceRect:Rectangle = new Rectangle(p.x, p.y, stage.stageWidth, stage.stageHeight);

this.fullScreenHandler(null, sourceRect);
}
}


private function fullScreenHandler(event:FullScreenEvent = null, sourceRect:Rectangle = null):void
{
var stage:Stage = FlexGlobals.topLevelApplication.stage;

if(event == null || !event.fullScreen)
{
if((stage.displayState == StageDisplayState.NORMAL) && event == null)
{
if(!stage.hasEventListener(FullScreenEvent.FULL_SCREEN)
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenHandler);

stage.displayState = StageDisplayState.FULL_SCREEN;
stage.fullScreenSourceRect = sourceRect;
}
else
{
stage.displayState = StageDisplayState.NORMAL;
stage.fullScreenSourceRect = null;

this.sourceComponent.width = this.componentWidth;
this.sourceComponent.height = this.componentHeight;
}
}


toggleComponentFullScreen
So what we do here is that we save the component's width and height in separate variables to be used later. When the component's state needs to be changed to FULL SCREEN, we set the components width and height to fill the stage. Next we convert the components local coordinates to global coordinates and create a Rectangle with them that can mask the screen.

fullScreenHandler
The handler is a generic function that can also be called from outside without the event. This function checks the displayState of the stage and based on that either masks it with the component's mask rectangle or removes the mask and sets the components width and height back to the original ones.

I found this useful in my application. Hope this can help someone. Cheers.


UIComponent.stage

An important class of note in Flex applications is the Stage. Every DisplayObject has a reference to the stage class and it is worth noting that the Flash runtime has only one Stage object. What the stage does is it acts as a container for all the display objects. Any display objects that we can see on the screen will have a reference to the stage of the run time and all of them will refer to the same object.
It is also important to note when the stage for a particular object is set. Before initialization the stage is null for every object. During the initialization of a component Flex fires an event called "ADDED_TO_STAGE". This is when the object is added to the main stage. If one needs to use the stage for anything, it is advisable to listen to this event so as to avoid null pointer exceptions.
A simple usage of the stage is to set the application to fill the screen,
       uiComponent.stage.displayState = StageDisplayState.FULL_SCREEN;
Other usage of the stage may be for resize operations or to fire a common event for all the Objects on display.

Friday, August 26, 2011

Free Export Button

Something I tried....
ExportButton provides you the ability to

1. Export to PDF
2. Export to JPG
3. Export to PNG
4. Send for print
5. Do a fullscreen

APIs:

exportType - This is the type of export. Choose from ExportUtilButton.TYPE_PDF, ExportUtilButton.TYPE_JPG, ExportUtilButton.TYPE_PNG, ExportUtilButton.TYPE_PRINT, ExportUtilButton.TYPE_FULLSCREEN

fileName - The name of the file to be saved. The extensions will be added by the program.

childComponent - The UIComponent to be exported.

onCancel - Function to be called on cancellation of file download

onComplete - Function to be called on completion of the file download.

icon - The icon that you want to be set on the button.

Sample Application Usage here
I'll soon try and put proper sample in some time. :)
You can download the swc here
Do feel free to add comments, reviews or any changes that you may require.

-Cheers

Adding multiple images with AlivePDF

Furthur to my work with AlivePDF, I had to add multiple images into the PDF that I was creating. This seemed straight forward at first. So I did it this way,


private function exportToPDF(childrenComponents:Array):void
{
var pdfEncoder:PDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4);
pdfEncoder.setDisplayMode(Display.REAL);

for (var i:uint = 0; i < childrenComponents.length; i++)
{
        pdfEncoder.addPage();
pdfEncoder.addImage(dObj, new Resize(Mode.FIT_TO_PAGE, Position.LEFT);
}
var bytes:ByteArray = pdfEncoder.save(Method.LOCAL);
_fileReference.save(bytes, (this.fileName + ".pdf"));
}

That worked fine but now I needed to bring them into the same page and add new pages dynamically. So here it went,

EDIT: Changed the code below to set margins and give out better resolution in the PDF.

private function exportToPDF(childrenComponents:Array):void
{
var pdfEncoder:PDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4);
pdfEncoder.setDisplayMode(Display.REAL);
pdfEncoder.setMargins(10, 10, 5, 20);

var pageNum:int = 0;
pdfEncoder.addPage();
pageNum++;
var imgY:int = 0;

for (var i:uint = 0; i < this.childrenComponents.length; i++)
{
var pageWidth:Number = pdfEncoder.getCurrentPage().w - 15;
var pageHeight:Number = pdfEncoder.getCurrentPage().h - 30;

var dObj:DisplayObject = this.childrenComponents[i] as DisplayObject;
var imgScaleFactor:Number = dObj.width/dObj.height;


var pw:int = 0;
var ph:int = 0;

if (pageWidth > dObj.width)
{
uiComp = (dObj as UIComponent);
pw = dObj.width;
if(pageHeight > dObj.height)
ph = dObj.height;
else
ph = pw/imgScaleFactor;
}
else
{
pw = pageWidth;
ph = pw/imgScaleFactor;
}

if ((imgY + ph) > pdfEncoder.getCurrentPage().h)
{
pdfEncoder.addPage();
pageNum++;
imgY = 0;
}

pdfEncoder.addImage(dObj, new Resize(Mode.NONE, Position.LEFT), 0, imgY, pw, ph);
imgY = imgY + ph + 10;
}
var bytes:ByteArray = pdfEncoder.save(Method.LOCAL);
_fileReference.save(bytes, (fileName + ".pdf"));
}



And it worked. All the "pw", "ph", "imgScaleFactor" have all been calculated so that I can get proper resolution on the PDF file. If you can better it, be sure to post it here.. :)
If the size exceeds that of the page, it should create a new Page and add it there. I haven't tested this properly, so it might be a bit buggy.
Cheers.


Printing image in Flex

This is a very simple excercise to do in Flex. The following code snippet demonstrates it.


private function printImage(component:UIComponent):void
{
if (component)
{
var printJob:FlexPrintJob = new FlexPrintJob();
if (printJob.start())
{
printJob.addObject(component, FlexPrintJobScaleType.FILL_PAGE);
printJob.send();
}
}
}


Explanation:

The code essentially takes the reference of the component which is to be printed. FlexPrintJob starts a new job.
printJob.start() checks whether the system is connected to a printer and that the printer is ready
FlexPrintJobScaleType sets the type of scaling that is required. NONE does not scale anything.

Thursday, August 25, 2011

Using AlivePDF to export PDF in Flex

I have recently been working with AlivePDF for exporting UIComponents into PDF and liked it very much. It is a simple tool, easy to use. A small code snippet

private function exportToPDF(uiComponent:IUIComponent):void

{
_fileReference.addEventListener(Event.COMPLETE, 
function callOnComplete(event:Event):void
{
if(onComplete != null) 
onComplete.call(null, event);
_fileReference.removeEventListener(Event.COMPLETE, callOnComplete);
})
_fileReference.addEventListener(Event.CANCEL, 
function callOnCancel(event:Event):void
{
if(onCancel != null) 
onCancel.call(null, event);
_fileReference.removeEventListener(Event.CANCEL, callOnCancel);
})

var pdfEncoder:PDF = new PDF(Orientation.PORTRAIT, Unit.MM, Size.A4);
pdfEncoder.setDisplayMode(Display.REAL);
pdfEncoder.addPage();
pdfEncoder.addImage(uiComponent as DisplayObject, 
                        new Resize("FitToPage", Position.LEFT));


var bytes:ByteArray = pdfEncoder.save(Method.LOCAL);
_fileReference.save(bytes, (fileName + ".pdf"));
}


I am assuming that we are using Flash 10. For player below that version, FileReference would not work. You'd need to do a server side implementation to download the PDF.

If anyone has any questions, please feel free to ask.


Monday, August 8, 2011

Binding itemRenderer with property not in data object

I really had a tough time with this one. Almost all the approaches I took with this failed.

So, what I really wanted to do was to add a line in the itemRenderer based on whether some property outside matched with the itemIndex or not. Getting the data in was not a problem. Binding it sure was.

Using outerDocument.property_name works only if the line was predefined, but since predefining Graphics elements caused a huge performance issue. I could not use that approach. Instead I added the code to draw the line in the updateDisplayList function.

Now the only thing was to bind the data. I tried to use outerDocument from the child and failed. Even the ClassFactory for the itemRenderer failed. So, then I tried adding event listeners on the change event of the NumericStepper in the parent and changed my display accordingly. Worked like a charm.


ItemRenderer Code:

private function creationComplete_eventHandler(event:Event):void
{
      outerDocument.nStepper.addEventListener(Event.CHANGE, this.onStepperChange);
}

private function onStepperChange(event:Event):void
{

       //Your code goes here.
}


I am still at a loss though on why the others failed. If anyone has any ideas, do share.