Tuesday, March 31, 2009

Showing the preloader again after loading is finished

This is probably not very important for most people, but when I was designing my custom preloader I found it quite difficult to get it looking exactly right - the positioning, font sizes, image location, etc. And so I was constantly reloading to see the preloader appear again.

So I wrote this simple test to show the preloader again after the application has loaded. This way you can control how long the preloader is visible for, and you don't have to add all these large images to make it slow to load.

** Here is the link to my previous blog post on Custom preloaders. It also contains some useful links to other websites and tutorials on custom preloaders.

Right Click to View Source:

Monday, March 23, 2009

Setting default styles for custom components

When creating custom components (e.g. extending Canvas) we sometimes want to define new style properties on our components. When I first started with Flex I would always call the setStyle() function from the constructor of my custom component. Then I noticed that if I tried to set my style property from inside MXML it didn't work.

So far I've come across two ways of solving this problem.
  1. Default Style Sheet - defaults.css (blog post)
  2. Class Construct
This blog post talks about the class construct idea:
Flex 3:
private static var classConstructed:Boolean = classConstruct();
private static function classConstruct():Boolean {
    if (!StyleManager.getStyleDeclaration("StyledRectangle")) {
        // no CSS definition for StyledRectangle, so create and set default values
        var myRectStyles:CSSStyleDeclaration = new CSSStyleDeclaration();
        myRectStyles.defaultFactory = function():void {
            this.fillColors = [0xFF00000x0000FF];
            this.alphas = [0.50.5];
        }
        StyleManager.setStyleDeclaration("StyledRectangle", myRectStyles, true);
    }
    return true;
}
Flex 4:
private static var classConstructed:Boolean = classConstruct();
private static function classConstruct():Boolean {
    if (!FlexGlobals.topLevelApplication.styleManager.
            getStyleDeclaration("myComponents.StyledRectangle")) {
        // No CSS definition for StyledRectangle,  so create and set default values
        var myRectStyles:CSSStyleDeclaration = new CSSStyleDeclaration();
        myRectStyles.defaultFactory = function():void {
            this.fillColors = [0xFF00000x0000FF];
            this.alphas = [0.50.5];
        }
        FlexGlobals.topLevelApplication.styleManager.
            setStyleDeclaration("myComponents.StyledRectangle", myRectStyles, true);
    }
    return true;
}
** Very important - in Flex4 you set the fully qualified class name (including package) in the style manager, this is different from Flex 3. It won't work if you only set it to the class name "StyledRectangle".

For a while that satisfied my needs, but then I recently came across a problem with the above code (which by the way was copied from the Adobe LiveDocs). If you scroll to the bottom you'll actually notice that someone else posted this same problem that I'm about to mention.

If you specify some styles using a StyleSheet, then the above code no longer works because no the StyleManager.getStyleDeclaration("StyledRectangle") doesn't return null, and so the default styles aren't set unless you specifically set them in your stylesheet.

To illustrate this problem I've gone overboard and created 5 examples to show you the evolution of my learning (Source code is available for all examples, just right click View Source. You can also click on the mxml link for each to jump directly to the mxml html view).



Example #1 (CustomComponents1.mxml)
I created a simple extension of the Canvas class which is called GradientCanvas1 that draws the background as a gradient using the colors and alpha values defined in the two styles
Example #1B (CustomComponents1B.mxml)
The problem with the GradientCanvas1 class is that it ignores the style values that I specify in the MXML, e.g. fillColors="[0xff0000,0x0000ff]".
Example #2 (CustomComponents2.mxml)
To solve the problem mentioned in Example #1B I've created another class called (creatively) GradientCanvas2 that uses the class construct idea mentioned at the top of this blog entry. This static class construct sets up the default style values and now setting style properties in MXML works.
Example #2B (CustomComponents2B.mxml)
The problem with the GradientCanvas2 class is that if you use a stylesheet to define some (but not all) of the styles on the GradientCanvas2 class then the class construct no longer works because the StyleManager.getStyleDeclaration("GradientCanvas2") doesn't return null anymore, and so our default styles aren't used.
Example #3 (CustomComponents3.mxml)
And finally, the solution that I'm using (might still be problems with it). In the class GradientCanvas3 the class construct now creates a new CSSStyleDeclaration for the class if it is null, and then defines the default styles on the defaultFactory, and that is it (the livedocs say something about the defaultFactory will only be defined if styles are set in MXML components, but I haven't been able to find a case where the defaultFactory wasn't null).

If anyone has different opinions about this stuff please let me know.

Thursday, March 19, 2009

Another Custom Preloader

I've been playing around with preloaders a bit recently, and thought I'd share my custom preloader. I originally found this very useful article:
http://www.pathf.com/blogs/2008/08/custom-flex-3-lightweight-preloader-with-source-code/

My CustomPreloader class is copied from the example above, and modified to be more easily customizable (I hope!). The colors and sizes are mostly defined at the top of the class.

The important functions inside CustomPreloader are as follows (they are all near the top of the class):
  • clear() - draws the background color/gradient
  • createAssets() - creates the assets (logo, progress bar, loading textfield) and positions them on the stage
  • draw() - draws the progress bar as the application is loading

  • Here is a screenshot of the preloader, click on the image to view the flex application in a new window:

    CustomPreloader


    ** I've subsequently written a test application which is very useful when designing your custom preloader, check it out here: Showing the preloader again after loading.

    Quick links:
  • CustomPreloader (View Source HTML)
  • CustomPreloader.as (direct download)

  • More Custom Preloaders and Tutorials
  • Wisebisoft Custom Flex 3 Preloader (Example)
  • A Preloader Museum
  • JesseWarden: Making A Cooler Flex Preloader (Example)
  • Totally Custom Preloader
  • Cool Loading Animated Gifs
  • Ted On Flash: Flex 2 Preloaders


  • Wednesday, March 18, 2009

    Flex Converter: Currency, Weight, Temperature...

    I've written a little Flex app that handles converting between a variety of formats:
  • Currency (using the www.webservicex.net Currency Convertor service)

  • Weight (Pounds/KG)

  • Distance (Kilometers/Miles)

  • Temperature (°C/°F)

  • Pace (minutes per km/mile)

  • Baking measurements (tablespoons, teaspoons, cups, ml)


  • The currency conversion can be quite slow because it is using the free web service mentioned above. All the other conversions are simply mathematical.

    See the example below (right click to view source):

    Tuesday, March 17, 2009

    Resizable Containers (Flex 3)

    Please go here for Flex 4 Spark Resizable Controls.

    I previous posted a blog on a Resizable Movable Panel control which was an extension of the TitleWindow class which let the user drag the panel titlebar to move it around the screen, and drag a small resize handle in the bottom right corner to resize the panel.

    I've made some updates to this class, and further extended it to support not just Panel/TitleWindow containers, but also Box (VBox/HBox), Canvas, and TextArea (similar to what Google Chrome does).

    The main class that does all the work is called ResizeManager. It adds a small resize component in the bottom right corner of the container that when dragged resizes the container.

    Here is an example (right click to view source). Let me know what you think!


    Important: the resize containers do not resize properly if you set the resizeEffect property.

    For a similar project that is devoted to movable windows, check out the MDI project which is now part of the FlexLib project.

    November 30th 2009 Update: I've updated the MoveManager adding two new fields. Setting the MoveManager.constrainToParentBounds to true will cause the component's movement to be restricted to the parent's bounds. You can also set your own custom bound's constraint by setting the constrainToBounds property to a Rectangle. The way this works is by passing that bounding Rectangle into the move component's startDrag(false, bounds) function.

    December 23rd 2009 Update: I've updated the MoveManager and ResizeWindow classes to fix a problem that occurred when movable="true" and resizable="true" and no dragComponent was set. Now the move and resize should work properly.

    January 5th 2010 Update: I've updated the MoveManagerand ResizeManagerclasses to use custom cursors for moving and resizing. You can also set the MoveManager.moveIcon and ResizeManager.resizeIcon properties to use your own custom icons, or just edit those classes directly and change the [Embed(source="...")] metadata tags.
    The move cursor is only shown when the mouse is down. The resize cursor is shown when the mouse is over the resize handle and when the resize is happening. There might be some problems with the resize cursor getting stuck always on, but hopefully it's a good starting point.

    March 4th 2010 Update: I've separated the move/drag and resize handles into separate stand-alone components: DragHandle and ResizeHandle. The colors of the handles can be customized using styles. You can also control how many rows and columns of dots are shown in the handles. Alternatively you can explicitly set a width and height for the drag/resize handles and the number of dots will be calculated automatically to fill the space. The size of the dots is configurable too.

    I also added a new properties to the resize components - bringToFrontOnResize, and bringToFrontOnMove (ResizableWindow only). These properties determine whether the components should be brought to the front to be on top of the other siblings. By default these properties are false. It only makes sense to set these values to true if the parent container is using an absolute layout.

    I've put up a blog post about the DragHandle and ResizeHandle if you're interested.

    September 15th 2010 Update: I added a new component - ResizableButton. There were a few things that had to be changed to make it resizable and movable since it is not a Container. The main difference is that the Button class by default has the mouseChildren property set to false, which prevents the move and resize handles from getting mouse events.

    Wednesday, March 11, 2009

    VPN Blocking port 80 (not Flex related)

    This post has nothing to do with Flex, but caused me to waste many hours yesterday so I thought I'd post it in case it helps someone else.

    I recently uninstalled Cisco VPN (on my Windows XP machine), and after rebooting I could no longer use port 80. At first I thought I couldn't access the internet at all. Then I realized that I had an IP address, and I could ping google. Then I realized I could still FTP (port 21 and 22), and then I tried accessing a website that uses port 8080 and it worked. So I realized my problem was that port 80 was being blocked. After a little searching I came across this blog that helped solve me problem:

    http://beer234.blogspot.com/2008/10/port-80-blocked-windows-xp.html

    The gist of it is that if VPN isn't properly uninstalled then it leaves behind a firewall that blocks port 80. I have no clue why mine wasn't uninstalled properly. Anyways, if for some reason the link to the blog above doesn't work, here are the steps:
    1. Restart the Windows XP PC in Safe Mode (press some combination of Shift, F5, F8 when booting up your computer)
    2. Run Regedit.exe to open the registry editor
    3. Navigate to HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\vsdatant
    4. Select start in the right pane and modify the value to 3 (mine was set to 2)
    5. Restart the PC and port 80 should no longer be blocked and you can use http with any browser

    Amazing that so many hours could be wasted and all it took was changing a 2 to a 3 in the registry!

    Friday, March 6, 2009

    Filtering and Highlighting Lists and DataGrids

    I've written a FilterBox control that filters the data inside List and DataGrid components, and another one that highlights items.

    See the example below for filtering and highlighting a List. I've included a few extra item renderers for showing checkboxes, and for highlighting DataGrid columns.
    (View source enabled)



    There are some limitations, such as it only highlights the first occurrence of the text. And I probably could have used data binding instead of passing in a function to the TextHighlighter, but hey - it's a work in progress.

    If you use the FilterBox control, you might notice that it depends on a ButtonBox component. This is my implementation of a CheckBoxList, which has the same basic functionality as a List, but maps each data item in the list to a CheckBox, and doesn't re-use item renderers the way Lists do. This way you don't have to have a selectedField property in your data. I've noticed that the ButtonBox control doesn't scale very well if you have more than a few hundred items in the list.