One of my first posts was about using ExternalInterface to call Flex from Authorware, and about how there is virtually no documentation on how to use this API to run functions inside a Flex swf from an ActiveX control embedded in an executable (in this case, Authorware). I've found some more anomalies which are worth jotting down for my own future reference and the reference of anyone who's bored enough to read my blog.
It seems that the <arguments> parameter does not recognize the full spectrum of data types supported by Flex. So far, I have found that if your Flex function expects an int or a Boolean argument, these values must be wrapped in a <number> tag. I guess Flex knows ExternalInterface can't handle these data types, and converts them from generic numbers into the appropriate data type by pfm in the background.
Ain't life grand?
More on ExternalInterface
english mobileShowing item number in ItemRenderer
english mobileI asked a question several weeks ago on the FlexCoders forum on how to get the item number of an item that had been clicked in a Repeater. None of the answers that I got seemed to help and it wasn't that critical, so I let it drop. In my current project, it is critical, because I have to show that number on the screen.
Luckily, I am using XML. E4X XML, like Authorware icons, is very "self-aware." In Authorware, you can get from any place in the program to any other place using the numeric values implicit in the parent/child relationship. Similarly, an E4X XML node "knows" what its child number is relative to the parent node. So displaying the node number on the screen was as simple as {data.childIndex + 1}.
Some days Flex is really cool :-).
Updated 12-3-08:
I've posted a simple example that shows how to display the line number in a List based control with either an XML or ListCollectionView source.
Order of Events for ItemRenderers
english mobileI suspect that I'll be blogging a lot about ItemRenderers, because it seems that there's a ton that can go wrong with them and lots of stuff to learn before you can get it right. A good starting point in learning about them is Alex Harui's Blog. I found this source a bit misleading in my current project, because it suggests that you should run your init code in the dataChange event listener function.
The problem I found is that the dataChange event runs before some objects in the component have been instantiated, so trying to change their attributes results in a spectacular explosion. The solution I found is to set a boolean value in the creationComplete listener to indicate whether or not the component was completely drawn, then run the same logic that would have run from the dataChange function. So when the data changes, the dataChange listener will initialize the objects, but on first creation, the creationComplete listener handles it.
I suspect this is not the optimal way to handle this, but it works and doesn't require much rocket science on my part.
Update 7/3/2008: I eventually had a series of conversations about this with Alex, and it seems that the mistake I was making was that I was trying to address objects directly in the dataChange event handler, and, as noted above that doesn't work. But instead of repeating that call in dataChange and creationComplete, what I should have done is to set a boolean flag in dataChange only to indicate that the property (which in this case was a dataProvider) needs to be set on the child object.
I was trying to avoid overriding any of the inbuilt methods, but the engineers intended for developers to override many of the methods when creating itemRenderers. In this case, I needed to override commitProperties and set the dataProvider whenever that flag was true (and then set the flag back to false, of course).
Unhandled Error
english mobileI am often trying to do sort of off-the-wall things in Flex, because I am slowly building new functionality in Flex that gets plugged into Authorware. When enough of the functionality exists in Flex, we'll rebuild the shell logic to finally port it all to Flex. But for right now I find myself doing things I suspect the Flex team never intended.
For instance, last week I was sending XML in through ExternalInterface that contained XML that was destined to be the htmlText for a TextArea (I have more fun and interesting posts about that to come later). But the upshot is that I was getting "Error #2044: Unhandled IOErrorEvent:. text=Error #2036: Load NeverCompleted." I thought it was a problem with the XML getting through the ExternalInterface or maybe with the parsing or possibly with the component that was displaying the content. I couldn't find anything on this error, so I was pretty much stumped.
As it turns out, the problem was that I'd gotten the path to an image in the HTML slightly wrong, and when that didn't load, I got the error. A secondary issue was that the latest Flex Beta spits out a debug swf by default, so this helpfully shows the error to anyone and everyone unless you go out of your way to put out a production version. I'd forgotten about this new quirk, so this was fairly alarming in a file I'd planned to pass along to my client.
Anyway, we're going for dinner now. Ta.
Undocumented Image Control Properties
english mobileFor over a week, I've been struggling to make an image gallery similar to the one here. The problem I was having is that the images were all different sizes, and when they were displayed on the screen they were jumping all over the screen. Let me go back to the beginning...
It seems that the Image control doesn't scale properly unless you set its size as a percentage of the container size. So, if you leave the size off to let the image size itself, you get a giant image with scrollbars, regardless of whether you've set scaleContent to true or not. So, when you set the image size as a percentage of the container size, the image control probably won't have the same dimensions as the image, which means that the image is "floating" inside the container. By default, the image is supposed to be in the top left of the image control, but my experience is that it can wind up pretty much anywhere in the control.
I scoured the documentation and even asked on FlexCoders, but no one could tell me a fix for this problem. Finally, in desperation, I went back to the example, and found this text nestled in the image tag's properties:
verticalAlign="bottom" horizontalAlign="center"
Grrr... I hope this saves someone else from over a week of fruitless frustration!
Update 7/3/2008: I ultimately learned that if I want to affect any visual property of a component, that I needed to look at both properties and styles. These two "properties" are, in fact, documented--styles.
Dispatching Events
english mobileI'm thinking I'm probably extra stupid, but I kind of got the impression from the Event handling docs that if you wanted to send out your own events, you had to have your own events class. It seemed to me there was something magical in the constants defining event names in your events class that somehow made the events so named "your" events. It turns out that if you want to dispatch an event "this is an event" then it really is as simple as
dispatchEvent(new Event("this is an event"));
Then all you have to do is add an event listener for "this is an event". There's no more magic to it than that. The event just needs to be called the same thing on both sides, and that is what the constants make sure of. But they're not required.
Now, if you want to pass more information in an event, such as whether a click on a Multiple Choice Question is right or wrong, then you'd need your own Event class. But for simply broadcasting an event you know is yours, you just send out an event as above. Duh.
I figure most people reading this are not as "challenged" as I am, but hopefully this helps someone anyway.
Update 7/3/2008: When a component is dispatching events, it should also "announce" what events are available on it with an Event metadata tag, such as [Event (name="thisIsAnEvent" type="flash.events.Event")]. This allows you to use it in MXML without a compiler error. I honestly don't know whether multi-word event name, as stated in my original example, would cause an error or not.
Modules for eLearning
english mobileI've written before about how difficult I've found it to figure out how to use Modules for eLearning style structures within Flex. It seems to me I may have hit upon an approach that works. The new documentation on Modules has an example that shows creating an Interface so that you have a known "contract" between the Module and the parent container. The example shows how to pass information into the Module, but didn't seem at all concerned about passing information back out. So I put my thinking cap on, and went to researching.
The first thing that seemed obvious to me was that you'd need to have some sort of event that would be propogated from the Module to tell the parent container that something had happened. So, I went and looked at the documentation about how to handle events. And I really, really tried to figure out a way to do it just with the implementation of the functions from the Interface. But functions in an Interface are kinda tricky. They're fairly plain Jane (in the Interface itself they're just stubs, with no implementation) and are really designed to be called from whatever is Interfacing with the Interfacee (as it were). I couldn't figure out a way to use them to push information out with them.
Instead, what I did was create a function that will return the name of the event that the Module expects to send out to the container. This allows the container to attach an event listener for that event without having to know up front what it will be called. So, for instance you could have an ElearningEvent.MENU_CLICK or an ElearningEvent.MC_SELECTION.
Where did the names for these events come from? Well, let me back up. I wrote a custom event class called ElearningEvent, specifically for handling events from my own eLearning Modules. I imported this class both into the Module file and into the Container file. It had public static constants in it that defined the ELearningEvent types. Ultimately, I plan to extend it so that more custom events can convey more information, such as whether a question was right or wrong (right now, it just publishes a value and ID).
So now that I've rambled all over the map, let me distill the process into a nutshell:
- First, I wrote the Interface .as file (IELearning.as), which essentially said "these are the functions you can use to access me, and here are the arguments I expect and what I will return."
- Next, I wrote the ELearningEvent class, which defined my custom event, including constants covering the event types included in it. I made it Inspectable so that Flex Builder would help with the typing.
- I added the implements element to the Module to specify that it implemented IELearning. I added the implementation of the Interface functions, including the one that published the specific event for this Module (in this case, a MENU_CLICK). And I added logic to listen for a click on the menu and generate my ElearningEvent.
- In the containing Application, I added logic similar to the logic in the Module docs to retrieve a reference to the Module child when it loaded. The difference is, I also asked for the name of the event that the Module child was planning to generate, and attached an event listener to the child.
The Module file was already inserted into the Application file, and I'd already worked out its base functionality before I started the process above.
I'm still not sure why an Interface is the suggested solution for this. I would think that maybe just writing an ordinary class, might be better, or even a fake abstract class.
Posted by
Amy B
at
8:13 AM
0
comments
Labels: Actionscript, eLearning, events, flex, Interface, Modules
