Firefox and the Flash/Flex focus problem

I’m working in a Flex project and the client asked for some Keyboard Shortcuts. It works great on Google Chrome and IE but, for some reason, Firefox doesn’t handle embedded objects focus correctly sometimes.

To “fix” this problem, I found a really nice workaround. First, you have to open your application on some browser and look at the source code. Then, look for the <object> tag “id” attribute inside it. If you use the default Flex template, it will probably be your Application name. In my case, it’s “index”. So I wrote this JavaScript line to set the focus on your application again:

1
document.getElementById('index').focus();

Now, to use it on your code without rewriting your template, you can do this:

1
2
navigateToURL(new URLRequest("javascript:try{ document.getElementById('index').focus(); void(0); }catch(err){}"), "_self");
someComponent.setFocus();

It works better if you try to identify when your application is loosing the focus (always when I opened a popup, in this case) and put the code after that. I also used a try/catch to avoid problems, like if the user opened the SWF directly.

I hope it helps someone!
Bye o/

Version-safe Monkey Patch on Flex components

What? Why?

Sometimes we want to add some custom behavior to a Flex component and everything you need is private or you find some bug that you can’t fix only with inheritance. Or maybe you can, but if you do, you’ll have to change all instances to your component. And sometimes you even can’t change the instance, like when you are using some closed library.

Today I was trying to fix a bug at the ComboBox component, using the Flex SDK 3.5. This bug was already fixed on the version 3.6, but I can’t update if they don’t release it as a stable version. This bug is very stupid and a simple method override with 3 lines of code would solve my problem. But, like I said, I can’t just change all the ComboBox instances in my application. And, even if I did, maybe some other developer could use the original ComboBox, instead of my FixedComboBox.

So I decided to temporarily Monkey Patch the ComboBox class. To do that, I just had to copy the original ComboBox class and all the includes, fix what I wanted and put it at the same package, but inside my project “src” folder. The compiler will use my patched version and ignore the original class.

The problem:

Okay, but what if we forget to remove the patched version when we update the SDK? Everything is Flex 4 now, so maybe they will only release the SDK 3.6 version in some months. And maybe in some months I will be working in a different project, don’t know…

The solution!

So I was thinking… How can I check if the SDK version was updated?

Every Flex component includes a file called “Version.as”, that have only one constant with the SDK version. Most people just copy this file when they are “Monkey Patching”, but if we do that, it will replace the SDK “Version.as” file and we will never know the correct version.

The trick is: don’t copy this “Version.as” file to your project. Then replace the include with the constant inside the file. Find this line:

1
include "../core/Version.as";

and replace with:

1
2
3
4
5
/**
 *  @private
 *  Version string for this class.
 */

mx_internal static const VERSION:String = "3.5.0.12683";

Now we don’t need to copy the file and we can have different versions for the SDK and the patched components. And you can add this code inside your constructor to check if the version changed:

1
2
3
4
5
6
if( FlexSprite.mx_internal::VERSION != mx_internal::VERSION )
{
    setTimeout(function():void{
        throw new Error("The SDK version was updated. Please update or remove the Monkey Patched ComboBox from this project.");
    }, 1);
}

That’s it!

FAQ:

Why FlexSprite?
I was thinking about using UIComponent, but maybe you’ll Monkey Patch it too. So I think you don’t need to change anything inside FlexSprite.

Why throwing an error?
You can change it to a trace(), but will you read the console all the time? And don’t worry, only people with the debugger Flash Player can read this error anyway.

Why the setTimeout()?
If you throw an error inside your constructor, it will break your application. I tried callLater(), but other things in Flex use the callLater() queue and, if you throw an error there, it will break the queue. So I think the setTimeout() is a safe place to put it.

Conclusion:

Monkey Patch is not the best solution. Actually, it’s not even a good solution! But it’s necessary sometimes and, if you really need it, I think the version check code is a good thing to help you.

Do you have some alternative solution? I would love to read it at the comments!

Cheers!

How to develop and debug Flex on Google Chrome

Developing and debugging Flex applications on Google Chrome sometimes can be a little tricky, but I will show you here how to solve this common problems.

Configuring Eclipse

First, you have to configure Eclipse. Open Preferences > General > Web Browser and select “Use external Web Browser”. Then, click on “New” and add “Google Chrome” using the following Location:

1
/Applications/Google Chrome.app/Contents/MacOS/Google Chrome


Your configuration should look like this:

If you are using Windows, you should click “Browse…” and find your Google Chrome application .EXE file.

Debug Flash Player

Google Chrome have it’s own Flash Player, so even if you download the debugger version, you may have problems to debug. So first, if you don’t have the debugger version, download it.

If you already downloaded and restarted Google Chrome, open this URL:

1
about:plugins


You may notice that you have two versions installed and one version “Location” is inside Google Chrome’s directories. So, you have to Disable this version and keep the other I’ve just installed. It should look like this:

Update: If you can’t disable plugins, download the Google Chrome development version here.

After that, right click any flash content and look for the option “Show Redraw Regions”. If you have this option, you’re using the debugger version.

Cache Problems

If you keep refreshing your application all the time, you may have some problems with caching. And, since I don’t think Chrome have some quick setting to disable cache, I’ve created a simple application that will launch Google Chrome with some command line parameters that temporarily disable cache.

To use it, download the application, unzip it and move the app to the Applications folder. Then drag the icon to the Dock, if you want quick access:

Notice that, since Google Chrome will keep only one initial instance, you have to launch it using my app at the first time if you want no cache. If Chrome is already running, it will still keep caching files. If you want your cache back, just quit and open Chrome using the regular app icon.

For windows users, I think you can copy your regular Google Chrome shortcut, right click the copy, select Properties, and add this command line parameters:

1
--disk-cache-size=1 --media-cache-size=1

This beautiful black Chrome icon was created by GreasyBacon. Don’t forget to check his other works.

Conclusion

That’s it! The only problem that I’m still trying to solve, is when you use the option “Find in Language Reference”. It will not open! If I find some solution, I will update this post. Do you know how to solve it? Leave a comment!

Cheers.

How to get BitmapData and ByteArray from Embed in Flex?

When you want to manipulate images and other file types in Flex, most of the time you need the BitmapData or the ByteArray from that file. Most people know how to get it when they are using the Loader, but it’s harder to find information about how to get it using Embedded files. It’s really easy to do that, let me show you how!

If you want to Embed some image (JPEG, GIF or PNG) in Flex, you have to Embed it into a Class. What most people doesn’t know is that the type of this Class will by the BitmapAsset and that BitmapAsset is a subclass of the Bitmap class. So you can do this:

1
2
3
4
5
6
7
8
[Embed(source="image.png")]
public var MyEmbed:Class;

private function getBitmapData():BitmapData
{
    var bitmapAsset:BitmapAsset = new MyEmbed();
    return bitmapAsset.bitmapData;
}

Now, to get the ByteArray, you need a little trick! You have to add the parameter mimeType="application/octet-stream" to the Embed metadata. With this parameter, the Class type will be ByteArrayAsset and that’s a subclass of ByteArray. So you can do this:

1
2
3
4
5
6
7
8
[Embed(source="image.png",mimeType="application/octet-stream")]
public var MyEmbed:Class;

private function getByteArray():ByteArrayAsset
{
    var byteArrayAsset:ByteArrayAsset = new MyEmbed();
    return byteArrayAsset;
}

This way, you can even Embed some TXT or XML file in your application and read it very easily! The ByteArray can be converted to a String:

1
2
3
4
5
6
7
8
[Embed(source="myTextFile.txt",mimeType="application/octet-stream")]
public var MyEmbed:Class;

private function readEmbeddedTxt():String
{
    var byteArrayAsset:ByteArrayAsset = new MyEmbed();
    return byteArrayAsset.toString();
}

Easy, huh?

How to remove Event Listeners with parameters / closure?

On my last post, shaokai asked me how to remove those event handlers added dynamically with parameters and I think it’s a really good question, so I’m posting the solution here too.

Actually, I never tried to remove the listener, but you can’t do this the same way you add the listener. So I found two different solutions to this problem. First, but maybe not the best solution, you can keep a reference to your handler, like this:

1
2
3
4
5
6
7
8
// Keep the reference
var myHandler:Function = buttonHandler(0x0000FF);

// Add the listener
myComponent.addEventListener(MouseEvent.CLICK, myHandler);

// Remove the listener
myComponent.removeEventListener(MouseEvent.CLICK, myHandler);

This solution is valid when you can keep references to your handlers, but when you have many handlers with different parameters, it’s hard to keep all the references. So I found a generic solution to remove event listeners, so you can do this, inside your handler function:

1
2
3
4
5
6
7
8
9
10
private function buttonHandler(color:uint):Function
{
    return function(event:MouseEvent):void
    {
        box.setStyle("backgroundColor", color);
       
        // Remove the handler
        event.currentTarget.removeEventListener(event.type, arguments.callee);
    }
}

Passing parameters to Event handlers

One year ago I asked Beck Novaes how to pass parameters to Event Handlers added dynamically, because when you add a Event Listener using myComp.addEventListener(...), the handler must wait only one event parameter. So Beck came up with a solution, but he stated that this is just one “alternative” solution, not the better one.

Some days ago I was working with simultaneous requests to the server and I wanted to keep the data I sent on the request but I didn’t want to return it from Java, so I came up another solution. Assuming that your Event Handler is waiting a Function that have only one Event parameter, I created another Function that returns a Function waiting the Event parameter. But the trick is that the Function Closure scope allows you to access parameters passed to the first and the second Function, so you can do this:

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
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" height="100%" width="100%"
    initialize="initApp()">

    <mx:Script>
        <![CDATA[
            private function initApp():void
            {
                buttonA.addEventListener(MouseEvent.CLICK, buttonHandler(0x0000FF));
                buttonB.addEventListener(MouseEvent.CLICK, buttonHandler(0xFF0000));
            }

            private function buttonHandler(color:uint):Function
            {
                return function(event:MouseEvent):void
                {
                    box.setStyle("backgroundColor", color);
                }
            }
        ]]>
    </mx:Script>

    <mx:HBox>
        <mx:Button id="buttonA" label="Blue"/>
        <mx:Button id="buttonB" label="Red"/>
    </mx:HBox>

    <mx:Box id="box" height="80" width="200" backgroundColor="#FFFFFF"/>

</mx:Application>


And now, what if you want to use this Event Handler directly in MXML? Well, you can’t do this:

1
<mx:Button label="Green" click="buttonHandler(0x00FF00)"/>


This will not work because the Function that returns from the first one is waiting the Event parameter. So you can do this:

1
<mx:Button label="Green" click="buttonHandler(0x00FF00)(event)"/>


Weird, huh? Maybe another FreaktionScript pattern?