10/27/2007

GWT, Flex and the FABridge

Earlier this year Alistair Rutherford wrote:
A recent thread on the GWT forum got me interested in the possibility of interfacing GWT to Adobe Flex. Adobe have released a javascript to flex ‘bridge’ component called FABridge.
I have put together a (very) quick and dirty demo the two components talking to each other through the FABridge. This is far from finished but is does demonstrate the basic concepts.
At that time, the integration of FABridge didn't work in IE. I don't know, what exactly has changed since then. But FABridge is working now in IE. Since I am currently developing a GWT-Flex application anyhow, it was a small step to write a GWT-FABridge library for general purposes.

Here you can see this small library in action. It is now possible to access actionscript objects from GWT, get and set actionscript properties, invoke actionscript methods and even register GWT objects as Flex event listeners. The most important new classes are BridgeObject which wraps ActionscriptObjects (or to be precise the ASProxyObjects from FABridge) and SWFABridgeWidget, which extends the SWFWidget from Rafal Malinowski's great gwt2swf library. Gwt2swf wraps the SWFObject javascript library for GWT. This means, that gwt-fabridge can be used with multiple swf-files, just like gwt2swf.

Rafal Malinowski is planning to write his own extension SWFCallableWidget in the near future. SWFCallableWidget will be compatible with Actionscript 2 and will essentially do for GWT, what FABridge does for Javascript. Probably, this will be a better approach than mine, since wrapping the FABridge has created some redundancy. Be that as it may, for the moment gwt-fabridge surely is a better and easier method for controlling swfs from GWT, than hacking your own native methods from scratch.

Here is the library and the simple demo for download. I would be glad to get some comments (I am fairly new to GWT). Please note, that you have to access the files through a http:// server address (like http://localhost) because of the swf's security sandbox.

I have made some small changes in the gwt2swf classes. These changes are already in the gwt2swf cvs, but not in the current jar release, so please use the jar in the rar.

The same goes for the FABridge.js. I had to change one line, because FABridge could not be called from iframes and hence not from GWT (I needed several days to figure this out and nearly gave up). More about this here. I hope that this iframe-support will be added in the next version of FABridge.

Here are some code snippets which show you how to use the new classes (all code comes from the example class, in which I used the app.swf from Adobes example):

Creating a New SWFABridgeWidget

//Parameter for SWFObject
SWFParams params = new SWFParams("app.swf", new Integer(400),new Integer(400));

// set bridge name flashVar for FABridge
params.addVar("bridgeName", "example");
swfWidget = new SWFABridgeWidget(params);

// add swfWidget to RootPanel
RootPanel.get().add(swfWidget);

//show swf movie
swfWidget.show();

Adding an Initialization Callback

// add initialization listener
swfWidget.addInitializationListener(new IInitializationListener(){
public void onInitialization() {
// get width of the swf
Object width = swfWidget.root().getProperty("width").getContent();
Integer test = new Integer(width.toString());
Window.alert("Swf Initialized. Width: " + test);
}
});

Getting and Setting an Actionscript Property

// get check box
BridgeObject check = swfWidget.root().getObject("check");
// get check box status
Boolean status = new Boolean(check.getProperty("selected").getContent().toString());
// change check box status
check.setProperty("selected", !status.booleanValue());

How to register an Actionscript EventListener

// add click listener to flex button
swfWidget.root().getObject("button").addEventListener("click",
new ISWFListener() {

public void onSWFEvent(JavaScriptObject event) {
Window.alert("Hello, GWT! Love, Actionscript...");
}

});

// add change listener to flex slider
swfWidget.root().getObject("slider").addEventListener("change",
new ISWFListener() {
public void onSWFEvent(JavaScriptObject event) {
// wrap event object into bridge object
BridgeObject e = new BridgeObject(event);
// get slider value from event object
sliderLabel.setText(e.getProperty("value").getContent().toString());

}
});

How to create a new DataGrid

BridgeObject flexApp = swfWidget.root();

// create new data grid
BridgeObject grid = swfWidget.create("mx.controls.DataGrid");

// create first column
BridgeObject col1 = swfWidget.create("mx.controls.dataGridClasses.DataGridColumn");
col1.setProperty("dataField", "apples");

// create second column
BridgeObject col2 = swfWidget.create("mx.controls.dataGridClasses.DataGridColumn");
col2.setProperty("dataField", "oranges");

// add columns to data grid
JavaScriptObject jsArray = JSNIUtils
.convertArray(new JavaScriptObject[] {
col1.getJSContent(), col2.getJSContent() });
grid.setProperty("columns", jsArray);
grid.setProperty("width", 300);

// create first row
BridgeParameterObject row1 = new BridgeParameterObject();
row1.addProperty("apples", 12);
row1.addProperty("oranges", 32);

// create second row
BridgeParameterObject row2 = new BridgeParameterObject();
row2.addProperty("apples", 15);
row2.addProperty("oranges", 24);

// set dataProvider
grid.setProperty("dataProvider", JSNIUtils
.convertArray(new JavaScriptObject[] {
row1.getObject(), row2.getObject() }));

// add grid to panel
BridgeParameter params = new BridgeParameter();
params.addParameter(grid.getJSContent());
flexApp.getObject("panel").invokeMethod("addChild",params.getParameter());

2 Kommentare:

author hat gesagt…

I have used your thinggie, and it got me out of writing JSNI code very fast. Still, I had to update FABridge.js with a newer one found here: https://bugs.adobe.com/jira/browse/SDK-12279 in order to be able to call static methods.
Also for this update you have to change in your BridgeObject class the getMethodName method, which uses the camel case calling convention - no longer needed for the new FABridge.js.

Christian Voigt hat gesagt…

cool, thanks for your tip. just saw this, after having uploaded version 1.1, so now I am uploading version 1.1.1 ;)