I have to tell you, I spend a lot of time debugging. So for a long time, I just left Flex Builder in Debugging persoective unless I needed to work in design view for some reason. But then I realized that Development Perspective gave me more vertical space in the code window, and I started switching to it more often. I'll admit, that's not exciting enough to post about.
But once I started working in Development Perspective more often, I started noticing that the Outline pane was much more useful than what I previously thought. Whenever I'd seen the Outline pane presented before, it was just a way to get hold of items in Design view that were underneath other items or otherwise hard to select. But Outline view is an aid I use daily now, because I can see the overall structure of a class at a glance, or click on a method or variable and instantly be taken to where it is defined in the code.
I don't know how I missed the documentation of this wonderful feature.
Why I love development perspective
english mobileImplementing IEventDispatcher
english mobileRecently, I had to have a class that took arguments in its constructor and also was able to dispatch events. Rather than trying to extend EventDispatcher and worry about separating the arguments the rest of the class needed from the ones EventDispatcher needed, I decided to implement IEventDispatcher. Problem was, I hadn't done this in a while, and I couldn't remember the right way to do this and had no idea what project had an example of it. So, I went searching on the web and refreshed my memory that you need to include an EventDispatcher instance in your class and route your IEventDispatcher methods through that object.
I created some boilerplate code that I can just cut and paste to add IEventDispatcher support to a class, and I share it with you now.
//--------------Support for IEventDispatcher--------------//
private var _ed:EventDispatcher;public
function addEventListener(type:String, listener:Function,
useCapture:Boolean=false, priority:int=0,
useWeakReference:Boolean=false):void
{
_ed.addEventListener(type,
listener, useCapture, priority, useWeakReference);
}
public function
removeEventListener(type:String, listener:Function,
useCapture:Boolean=false):void
{
_ed.removeEventListener(type, listener,
useCapture);
}
public function
dispatchEvent(event:Event):Boolean
{
return
_ed.dispatchEvent(event);
}
public function
hasEventListener(type:String):Boolean
{
return
_ed.hasEventListener(type);
}
public function
willTrigger(type:String):Boolean
{
return _ed.willTrigger(type);
}
Enjoy!
Updated 12/15/08:
Note that you'll need to put an instance of EventDispatcher in _ed in the constructor of the class that's implementing IEventDispatcher:
_ed=new EventDispatcher(this);
Updated 12/21/08:
Josh McDonald posted code that shows how to implement IEventDispatcher with boilerplate that doesn't require adding a line to the constructor.
More thoughts on Remoting
english mobileAs I mentioned in my last post, I've been working with AMF for the first time this week. I'd read about using AsyncTokens to be able to determine which call to a service resulted in which result, so from the very beginning I'd intended to use this. The problem I had was that when I looked at the docs for RemoteObject, I couldn't find anything that actually returns an AsyncToken. So at first I figured I couldn't do it.
But here's the thing. All of my commands to access the RemoteObject use static properties and methods, which essentially means that for each service there's only one RemoteObject that gets used from any object in the application that needs to call that service. These different parts of the application didn't know about each other, and I didn't want them to. Nor did I want to make these commands refuse any new calls before the old one was finished. So I had to make this AsyncToken thing work, or completely change the architecture of how I was calling AMF.
Finally, I found the documentation for mx.rpc.remoting.Operation (don't ask me how). It turns out that a remoting Operation is the method on the service that you're calling. When you call a RemoteObject operation, you're invoking the Operation Class's send method, so it seems that creating an AsyncToken from a RemoteObject call is as simple as myToken:AsyncToken=myRemoteObject.myService(whateverParameters). I'm not sure exactly how you're supposed to figure that out unless you happen to luck into the right information like I did, since there's no direct link between the language reference on RemoteObjects and that on Operation, and it's only referred to in passing in a parentetical expression in the RemoteObject "how to" type documentation.
One of my command classes needed to be able to accept a result and fault function from the instance that was calling the service, so I then needed to find a way to set a Responder on the token. The first thing I tried was simply to push a new Responder onto the token's responders Array. Let me save you a little time and tell you in advance this doesn't work. Instead, you need to use the AsyncToken's addResponder() method.
Thoughts on remoting
english mobileThe past week or so, I've been doing something that's new to me--retrieving objects using AMFPHP and integrating them with Flex. In the meantime, I've found that there are some things that are hard to find out about the whole process, so I thought I'd make a note of them here.
First, all the examples I could find easily used NetConnection. The code on these was so similar that I think there was one basic example that has been modified slightly by several different people and posted. I had better luck using RemoteObject, and I finally found an example of this.
The next thing I ran up against is that you have to use a RemoteClass alias on your Flex class that defines the object that is receiving the data. The docs are a bit misleading in that it sounds like you only need to use this if you are sending to a remote service and the service is Java based. However, if you read a bit further (I didn't at first), you can see that this applies pretty much to any AMF mapping. If you are sending data only from the service to Flex and you're not sending data back from Flex to the service, the only thing that matters about this alias is that it must match the $_explicitType variable in the object on the PHP side.
I also discovered a few things on my own. My classes extended EventDispatcher, and at first they didn't deserialize properly. We speculated that the fact that the class wasn't just a subclass of Object might have been the problem, but it turns out that extending EventDispatcher doesn't break serialization. My classes also had their own methods and some additional properties. We speculated that these were causing the problem, but it seems that serialization ignores these things. I think that if I were sending data back to PHP through the RemoteObject, I'd need to mark those properties as transient.
I think the real reason the serialization wasn't working was the last thing I discovered, which is that you have to have a dummy variable typed as your custom class in the same class as the RemoteObject that you're using to retrieve the values. This makes sure that the class definition gets compiled into the class where it can be used.
Oh, and one more thing... To a PHP programmer who's not familiar with ActionScript, a setter looks like something he can't serialize to. So it's probably better to just write up a description of the properties you're expecting to have set than sending the PHP person your actionscript class as is.
Filtering Bookmarks, Warnings, and Errors in Flex Builder
english mobileMoving from Authorware to Flex
english mobileI started out as an Authorware developer, and one reason I am now doing Flex is that Adobe announced the End of Development of Authorware just over a year ago. I saw that Flex offered a lot of the advantages of Authorware--it does a great job of integrating various media into a cohesive whole and you can make an application that runs from the web or the desktop from approximately the same code.
Adobe's decision left many people scrambling to figure out where they would go, so Randy Nielsen from the Flex documentation team worked with a few Authorware developers to get a stub page up when Flex 3 was released so that Authorware developers could document what their experiences have been to help ease the process of making the migration for those who felt that Flex was the best Authorware replacement for them.
At long last, I managed to make some time to add my 2¢ worth to the document. So I'm happy to announce that the Moving to Flex from Authorware page at the Flex documentation wiki has been updated. There is one section that I wrote that for some reason isn't included, and I feel it may be useful to some people, so I'm posting it here:
Using Flex files inside Authorware
In large existing projects, it might not be feasible to migrate the entire project to Flex over night. One strategy is to create new functionality in Flex and embed that in Authorware. When Authorware finally is abandoned, the Flex functionality will still be useful.
Flex Side
Flex and Flash have an object, ExternalInterface, that allows them to communicate with whatever application contains the swf file. Normally, this is used in a swf embedded in the browser to communicate with javascript that is written in the HTML page.
At the moment that the swf loads, the child components of the swf don't yet exist, so any attempt to set any properties on them will cause an error, which will probably stop your Flex application from proceeding any further. So you should wait until everything is created before initiating communication with the container. This means that you should run a function on creationComplete that will use ExternalInterface to call out to the container and tell it that it is ready to receive data. This function should also set up the callback functions, which are the functions inside your Flex application that are accessible to the container.
The container should then respond by calling a function and providing data your Flex application needs as an argument. This can be a user name, lesson status, or XML that represents a menu. The function should perform whatever parsing is needed on the data and set object properties based on the data.
When the user interacts with the swf, it should again use ExternalInterface to tell the container what happened.
Once you have created your Flex file, you should make sure to export a release build by going to Project>Export Release Build. This file will be smaller and run more efficiently than the debug build that is built by default.
Authorware Side
The Authorware file will have a Shockwave Flash Object ActiveX control icon in it. The development machine should have Flash Player version (Randy, what's the minimum version of the Flash Player for Flex 3?) on it, and you'll need to make sure that the users have at least that version installed.
Next, you'll need a calculation icon that sets up the path to your swf file so that Authorware can find it. This will start the loading process, which will culminate in the creationComplete event.
Once the creationComplete event fires, the swf will generate an event that can be seen in Authorware by using ExternalInterface. To catch this event, you'll need to use an Event Response on an Interaction icon. The response should be set up to respond to the FlashCall event. This seems to work best as a perpetual response on an Interaction that is below the ActiveX Sprite on the flow line, but above the calculation that sets the path to the swf.
The information contained in the #request property of the EventLastMatched variable will be an XML formatted string, so you'll need to use an XML parser object to access its contents. The same event response will trigger every time the Flex Application calls ExternalInterface.call, so you'll need to look at the name of the root element to see what "function" the Flex file thinks it is calling and branch based on that.
In the branch that you set up for the initial call where the swf tells you it is started, you should respond by issuing a CallSprite command to the Flash ActiveX Sprite icon that calls a function in the swf with the data you want to see in Flex. Other branches should contain logic to respond to different calls the swf sends with ExternalInterface.
Download the example files.
GroupingCollection example featuring GroupingFunction
english mobileSeveral months ago, I built a dashboard example for a client that featured a calendar with a month view like you'd see in a paper calendar on one side and a week view on the other side. I wound up writing some fairly complex classes to handle the different breakdowns in how the data displayed. I also wrote a custom renderer for the calendar page and a different one for the week view.
And then I had to do some work with the AdvancedDataGrid and fell in love with the way this component "thinks" about data, with its HierarchicalData, HierarchicalCollectionView, and GroupingCollection. And, of course, I adore its styleFunction, as you might have guessed from my earlier TileList_withStyle and DataGrid_withStyle classes.
A few weeks ago, someone posted an example that showed a way to use GroupingCollections with controls that were not AdvancedDataGrid or Tree components. Let me tell you, that got my little cogs twirling. If only (thought I) you could use a function to decide how the items in a GroupingCollection grouped. Then you could use it to group dates into years, months, weeks, whatever floated your boat. So I went digging into the docs, and found that the GroupingField actually does have such a property.
And so the GroupingFunction example was born. This example illustrates how you can create a single array of objects that contain the dates to use for a Calendar application, then group and filter the data in different ways by using that array as the source for multiple ArrayCollections and GroupingCollections. These allow you to display that data in several different ways without a lot of manual parsing.
It also illustrates the following concepts:
- Using a single itemRenderer with the TileList_withStyle component to present different appearances based on the styleFunction you use.
- Using a Repeater to populate an Accordion control based on a data source
- Using a single child component that gets reused between the children of
the Accordion
I'd also like to point out that I'd have never been able to create this example if I weren't still looking for work. I'm sure you're probably loving being the recipient of all these free examples, but please return the favor by passing my name on to anyone you know who is hiring :-).
Updated October 21, 2008:
I changed the itemRenderer to show how you can set the blendMode on text to apply effects to it without embedding the font. I only set the blendMode on the lower label , so that the difference would be apparent.
Posted by Amy B at 2:06 PM 3 comments
Labels: Accordion, Actionscript, Date, example, HierarchicalCollectionView, HierarchicalData, ItemRenderer, Repeater, TileList
Extended DataGrid with StyleFunction Example Posted
english mobileA few weeks ago, I posted an example of an extended TileList that adds the styleFunction I've become so fond of with AdvancedDataGrid. I decided I'd look and see if I could do the same with DataGrid, and I found that, while it was challenging, I was able to do it. So I've posted my new extended DataGrid_withStyle and StyleableRenderer classes for you to use and enjoy. As always, View Source is enabled.
Flex FAQ posted
english mobileIn the past few weeks, I've started trying to help out around the macromedia.flex.general_discussion forum by answering questions, and I realized that the same questions were coming up over and over. Rather than post the full FAQ in a mammoth blog post I'd have to come back and update over and over, I thought I'd simply make a PDF on my main website that I could keep current and just link to it from this post. Hope you enjoy!
Looking for Work
english mobileSo far, most of the Flex work I've done has been Flex applications embedded in Authorware applications. My current Authorware and Flex project is winding down, and I'm looking for a purely Flex project to work on next. If you have benefitted from this blog and you know of a Flex job, especially a telecommuting job, please either contact me or pass on my information to whoever's hiring.
Thanks! :-)
TileList with styleFunction
english mobileRecently I had a requirement to have buttons displayed in a grid with different color backgrounds based on the underlying data. Thus, the TileList_withStyle was born. The TileList_withStyle is simply a TileList extended to have a styleFunction. Note that I mostly just copied and modified the styleFunction code from the AdvancedDataGrid control. You can probably use the same technique to add a style function to pretty much any List-based control.
At the same time, I also needed to set the icon on the button based on the iconFunction that TileList already had. Unfortunately, the Button class does not have hte inherent capability to use the icon as it is passed in through the iconFunction. Thus, the IconFunctionableButton was born. I've posted an example file demo-ing these two classes. Right-click and select View Source to get the source code.
Charting Example
english mobileA couple of weeks ago, I said I'd compile some thoughts about charting. Normally, this would mean that I'd talk about charts in a general way. I'm not much on posting code, mainly because I'm terrified that I'll post something that will lead someone who's even more newbie than I am down the wrong path. Instead, I prefer to talk about code in general terms, then let people go off and make whatever mistakes I've inspired them to while I keep a clean conscience.
But this week someone asked me to give an example of showing how to add an axis in ActionScript, so I thought I'd do that just this once because my husband just had shoulder surgery and goes to bed early these days. While I was at it, I threw in a little bit of this and that other stuff I'd learned while building charts.
I don't claim my approach is the only approach or the best approach to the problem. But here's an example of how to create a chart entirely in ActionScript. Right click to view source. If you pick up bad habits from it don't blame me!!!
Resources for Learning Flex
english mobileI started this blog to document the hurdles I was finding as I was learning Flex 3. In the year since I started blogging on Flex, this task has become much easier. I wanted to take a minute to talk about two things that I've noticed that are real improvements. First, the Start Page appears to update itself occasionally.
I've posted before that I had problems learning to use the debugger due to lack of resources that explain its basic functionality. A few weeks ago, I cranked up the Start Page for some other reason and noticed it had scroll bars. I scrolled down, and lo and behold! there was a link to a video tutorial on the debugger!
The second, I noticed just today when I was looking at the web version of the Flex Builder forums (I usually use NNTP). I noticed there's a forum for Flex in a Week, and since I'm nosey I opened it up and discovered a link to the Flex in a Week training course. I haven't had a chance to look at all the resources, but the topics look like they should be useful to the new learner of Flex. Thanks to the folks at Adobe for being proactive and helping new users over the learning curve hump!
Some thoughts on charting
english mobileThis past week, I made my first foray into the world of Flex charting, and I'll have to say that I found it a pleasant surprise. From all the comments I've seen from others using charting, I had expected a difficult, painful process. My experience was quite the opposite. This is the first time in my year or so of using Flex that I've been able to accomplish anything significant without having to customize or rewrite anything. It seems that almost anything you'd want to do with a chart, there was a property or style that would handle it. I did find the fact that nearly everything was a style a bit confusing at first, but once you realize this, it goes fairly smoothly.
I might not have found the whole experience quite so smooth if I hadn't found some nice examples by good people who were willing to post their code for the world, so I thought I'd acknowledge them here:
- Taking Control of Flex Charting Styles
- Flex 2 Charting with XML Tutorial
- Animated Chart Series
- Flex Chart Sampler
I learned a lot about charting this week, and I hope to have time someday to share more of it, but I did find two quick things that might be helpful to you if you're trying to get your charts looking exactly right. The first is if you use a line chart with itemRenderers that mark each data point in the chart, the first and last one will be cut off through the middle where the chart control clips the content. The solution is to set clipContent on the chart to false. Seems obvious, but took me two days to find it.
The second is that if your first legend item in a Legend control has a short label, you'll wind up with overlapping legends where the Legend control lays them all out as if they had a short label. You can use the markerWidth style to make all of the legend items the same size, and you can just make sure that size is large enough that your legends don't collide. No, this won't give you a pixel-perfect layout, but it is a heck of a lot quicker than fixing either Legend or LegendItem to correct this.
Getting Help in Flex Builder
english mobileWhen I open the Help Contents in Flex Builder 3, the first thing on the page is Tip! Learn how to filter and reduce your search results by reading "Searching Help." The problem is that on my installation of FB3, this is a dead link. I checked it this week on my husband's installation, and his link is dead as well. I eventually figured out what this page would have told me, but I feel like I was really slowed down in those early months when I had no control over the search results that would flood the results page when I searched for anything. A couple of weeks ago, I found the Flex 2 version of the page, when I no longer needed it.
But I thought I'd share a bit about how my help contexts are set up, because I find that these really cut the amount of time I need to mine relevant information. I have two main contexts that I use most of the time. The first is "How to." This gives me access to the "how to" instructions on most of the topics that I would be working on. I have unchecked AIR for now, since I'm not working in AIR these days.
My second help context is just the Language reference. I find that my pattern is to read the how to for a general overview of how to approach a problem, then I switch to the language reference context for the specific details (like property values and what they do). Sometimes I use the "Find in Language Reference" option on the Help Menu, but I don't like it as well, because it resets my help context.
It seems to me that there are certain search terms that are very difficult to get to in the Language Reference context, because they are inherited by many components. Since the name of the component that is being inherited from occurs early in the documentation for it, it will often appear in the search results before the results for the component itself. So I've learned that there are a few ways around this. If I am searching for List, I type in ListBase. List will actually come up in the search results ahead of ListBase. If I am looking for UIComponent, I click on the first thing that inherits from it and use the link in the "inheritance crumb trail" to go to it. If I am looking for AdvancedDataGridItemRenderer or AdvancedDataGridGroupItemRenderer, I look for AdvancedDataGrid and click the advancedDataGridClasses Summary. This gives the advantage of allowing me to easily get from one class to another.
In the next few weeks, I'm going to try to post a few Tips and Tricks about how I use Flex Builder itself to be as productive as possible, independent of any code I might be using. I'd like to invite you, the readers, to consider these posts to be an invitation to discuss their own tips and tricks by posting comments. Hopefully, we can all trade our best productivity tricks and become more productive together.
Debugging itemRenderers
english mobileYou may have notced that I have spent a lot of time chasing down issues with itemRenderers. It always frustrated me that you could get information on the parent of any component, but I could never figure out how to find out information on the renderers being displayed by a List based control.
I finally realized that if I set a break point in a scope that had a reference to a List control, I could rifle through the properties of that control until I found the rendererArray property, which seems to be an array of arrays. If you're not using a multi-column control, like a DataGrid or an AdvancedDataGrid, the itemRenderer for each row will be at the 0 index of each row index. Otherwise, each row will be the outer index of the rendererArray and each column will be an element in the row array.
I really do view this as my diary of Flex, and I got tired of not ever remembering what the name of the property is. It can take quite a while to fish through all the properties available on a control to try to relocate it. So I wrote it down, since it doesn't seem to be documented. Hope it helps you, too :-).
Are you Flex-ing in Europe or the UK?
english mobileThe European eLearning Summit (EeLS) is offering quality Flex training at a great price at Nottingham University on August 22nd. The class will be taught by Matthew Boles, and pricing starts at UK£50 (plus VAT), and the price includes lunch.
Musings on AdvancedDataGrid (Part 5)
english mobileUp to part 4, I've been talking about the AdvancedDataGrid itself and the properties it has that are supposed to make your life easier, like styleFunction and iconFunction. And they do, once you understand them. But now I'd like to turn my attention to the data source I was using to drive my AdvancedDataGrid (ADG).
My AdvancedDataGrid is being used as a menu on an eLearning application. The application has various tasks that the user must complete. Once a task is complete, it is shown again in review mode, which provides the student with remediation on what he did wrong or right. The student can also view reports of what he did in a given task. So each task will be available in three modes: normal, review, and analysis. The mode will be determined by the top-level container.
To this end, I created an array of MenuContainer Value Objects (VO) that contained a number of Task VO's. I assigned these to a HeirarchicalData dataProvider in the ADG. I immediately realized that the itemClick event just gave me the Task VO, and the Task knew nothing about its parent (and rightly so). Apparently, the itemRenderer also knew nothing about where the Task fell in the data structure, nor anything else in the ADG.
I realized it was a slippery problem, since even if I were to loop through the MenuContainers and find the Task that was selected, I would only find the first instance of it. So I decided to wrap my Task class in another class that had two properties, task and UID. In this class, TaskUID, I simply used UIDUtil to create a UID for this instance of the task.
Once I had that accomplished, I decided to take one more squint at the docs before I built a function to loop through and find my TaskUID. I trolled the language reference only on the word hierarchical. I'd looked at the HierarchicalCollectionView before, but the description implies that this is for making flat collections look hierarchical (heck, it actually says it!). However, this class does include a method, getParentItem(), which looked perfect for my needs.
In a wild leap of faith, I cast the event.currentTarget.dataProvider from the itemClick event from HierarchicalData to HierarchicalCollectionView and the method worked! It gave me a reference to the MenuContainer from the TaskUID. I have no idea what the differences are between those classes, so I wouldn't guarantee all methods would work when you do this kind of casting, but this worked for me!
Posted by Amy B at 11:23 AM 1 comments
Labels: AdvancedDataGrid, Event Listeners, HierarchicalCollectionView, HierarchicalData, UIDUtil, Value Object
Musings on AdvancedDataGrid (Part 4)
english mobileSo, in part 3, I gave up on my extension of the AdvancedDataGridItemRenderer altogether and set my extended AdvancedDataGridGroupItemRenderer as both the itemRenderer and groupItemRenderer on the AdvancedDataGrid. This gave me a nice uniform appearance on all of my itemRenderers. So I set off happily to write my iconFunction.
This turned out to work exactly as advertised, with only one hitch--my leaf icons weren't rendering. Had I misunderstood? Did the iconFunction (as opposed to groupIconFunction) work only for grouping rows? Well, no, as it turns out.
If you'll recall, way back in Part 2 I had a problem getting my styles to show up in my first column, so I set the itemRenderer on that column to my extended AdvancedDataGridItemRenderer. Even after I did this, though, some cells still didn't show my styles. At the time, I didn't understand what that meant.
Lesson Number 3: All itemRenderers in the tree column will use the specified groupItemRenderer, unless you specifically tell that column to use something else. Even if you do tell that column to use something else, it will still use the groupItemRenderer for (ahem) grouped items.
Once I figured that out, it was obvious to me that by removing the itemRenderer property on that column, I would then have 100% of cells using my extended AdvancedDataGridGroupItemRenderer, which had the existing icon functionality plus my added functionality for setting the background based on a style passed in through the styleFunction.
Great! Wonderful! But I then found that my particular data structure depended on knowing something about both the parent node and the child node in order to know what to do with an item click, and I couldn't figure out how to get the information about a strongly typed parent from a strongly typed child that might be the child of more than one parent.
Tomorrow, I will write about how I got this information.
Musings on AdvancedDataGrid (Part 3)
english mobileReview Part 2
The author of the blog post I originally found that inspired this journey said that this method would not cause the selection and rollover indicators to be obscured in the same way as this method. But I really wanted to be able to see these indicators, rather than a tiny edge around each row. So I was determined that I was going to get my AdvancedDatagridItemRenderer to allow me to see these indicators through it.
The first thing I'd tried, just setting the alpha property, hadn't worked. The next thing I tried was to try to use the graphics functions to draw a background like I did in the AdvancedDatagridGroupItemRenderer. Unfortunately, since the AdvancedDatagridItemRenderer does not inherit from UIComponent or DisplayObjectContainer, so it neither had a graphics object of its own nor any way to add one.
So I stuck my nose back into the docs and discovered that my TextField had a colorTransform object that I should be able to manipulate to change the alpha transparency. Well, I was able to change its alpha property, but there was absolutely no visible change.
Finally, I realized I was going to have to leave the Flex world and see what the Flash world had to offer. So I came across this post and was able to get the transparency by changing the blend mode. Still, my AdvancedDatagridItemRenderer and AdvancedDatagridGroupItemRenderer did not match, because the text in the AdvancedDatagridItemRenderer was semitransparent and the AdvancedDatagridGroupItemRenderer text was not. Lesson Number 2: Anything that inherits from TextField is only going to be able to support alpha transparency with difficulty, and even then the entire component, including the text, will be alpha transparent.
So I had the simple idea that I could use the AdvancedDatagridGroupItemRenderer to do all the item rendering.
Tomorrow, I will talk about getting the icons to render properly.
Posted by Amy B at 12:44 PM 7 comments
Labels: AdvancedDataGrid, colorTransform, CSS, ItemRenderer, UIComponent
Musings on AdvancedDataGrid (Part 2)
english mobileReview Part 1
I'd found a neat little sample that shows how to change the background color on the row by extending AdvancedDataGridItemRenderer (ADGIR) to set the existing background and backgroundColor properties based on a style set on the component.
I had no trouble copying this, but I found that for some reason the entire first column stubbornly refused to pick up my carefully applied color. Undaunted, I set the itemRenderer property of the first column explicitly to my extended ADGIR.
The result I had was closer to what I wanted--most of the cells in that column now had the color my styleFunction had insisted upon--but the ones with the triangle in them remained white. Aha! Clearly this was a different thing altogether, so I went back to the docs and looked for inspiration. It seems that the uncolored cells were being rendered by another component, the AdvancedDataGridGroupItemRenderer (ADGGIR).
So I set about extending that worthy component. At first, I thought I'd be able to just cut and paste the code I'd modified for my ADGIR, but no such luck. Unfortunately, the ADGGIR had no background or backgroundColor properties. So I fell back on more conventional tactics, drawing a rectangular background on the component when the style changed. First lesson: the AdvancedDataGridItemRenderer is based on the Flash TextField component and the AdvancedGridGroupItemRenderer is based on UIComponent. These two components have completely different capabilities and must be dealt with in entirely different ways.
As soon as I saw my extended ADGGIR next to the extended ADGIR, I realized that the ADGIR was not yeilding to my attempts to set its alpha transparency. I'd included code in both to set the alpha transparency, but it was only working in the ADGGIR.
Tomorrow, I'll talk about my attempts to add alpha transparency to the ADGIR.
Posted by Amy B at 11:51 AM 5 comments
Labels: AdvancedDataGrid, CSS, ItemRenderer, TextField, UIComponent
Musings on AdvancedDataGrid (Part 1)
english mobileThis last week, I had my first experience with the AdvancedDataGrid component. I knew I needed to have multi-column heirarchical data display. I also needed to be able to dynamically color and also set an icon each row based on the content of the data item. I scoured the docs for a component that would meet these requirements, and the ADG's styleFunction and iconFunction seemed like they would fit the bill perfectly--and ultimately they did. But in the meantime, they led me on a merry chase because the docs didn't include all the pieces I needed to understand what was happening. Ultimately I did understand it, so I thought I'd pass my surmises along in the hope that others can shortcut the many hours I spent on the problem.
Tomorrow, I'll talk about the relationship between AdvancedDataGridItemRenderer and AdvancedDataGridGroupItemRenderer.
Using a CSS TypeSelector with an itemRenderer
english mobileToday, I had more fun with item renderers. I had a component I was working on to try to prototype some new functionality, and I had set up styles for it in the <mx:styles> declaration of the Application tag. If I put my component in a container in the main Application, the style came through fine. If I used it as an itemRenderer of a List based class, only the text styles worked.
It seems that when you use a component this way, Flex will assign ListBaseContentHolder as the style name instead of the class name, but for some reason this only negates things like backround colors—text declarations come through just fine. This interesting feature isn't documented anywhere, so it took me a whole day to figure out the fix, which is so simple I wanted to pound my head against the wall till I couldn't see straight.
Hope this saves someone some time!override protected function commitProperties():void{
this.styleName = this.className;
}
Another good itemRenderer Resource
english mobileThe longer I use Flex, the more firmly I believe that the key to understanding it is the component life cycle. Specifically, the life cycle as it applies to item renderers. Today on Flex Coders, Douglas Knudsen posted a link to this great presentation on the component life cycle by Eli Greenspan. I can't for the life of me figure out how to bookmark to a pdf, but if I post a link here, I'll be able to find it forever :-).
Great ItemRenderer Resource
english mobileI really struggle with itemRenderers--what goes where to make what you want to occur happen when you want it to. So I've been talking to various people and reading, reading, reading trying to make sense of it all. From the posts on the yahoo FlexCoders group, it seems like I'm not the only one experiencing confusion.
I think the biggest problem is that there don't seem to be many "from the ground up" resources on this subject. But that doesn't mean there aren't any. In addition to the Flex help and LiveDocs, which, let's face it, confuse us as much as inform us, there are several blogs that tackle this subject. Today I found Peter Ent's blog, which contains a five part series just on itemRenderers. Thanks, Peter!
Working with Dates in AS3
english mobileThe Date examples that come with Flex (and, presumably, Flash) are all very well and good, but to me they don't seem to be very...practical. And it doesn't help that the documentation doesn't provide any clues about how to do simple things like, oh, figuring out how many days there are in a month. There's probably very good code for these things in opensource projects like the Flex scheduler, but I think you have to know where to dig.
So I played around with the Date object, and I discovered that you can use numbers outside the integers 1-31 in the date parameter (new Date(year, month, date)) and get some interesting results. Such as if you use 0, you get the last day of the previous month. As you might expect, negative numbers will go further back into the previous month. I suspect numbers higher than the last day of the month you're dealing with will continue into the next month, though I haven't tried it.
What I was trying to do was create an ArrayCollection that could be used as a dataprovider for a TileList and then that TileList could display a calendar page just like what you see when you look at the calendar on your wall...i.e. the first few days might be in the previous month and the last few days might be in the next month, because only February ever has a shot at fitting exactly in a grid that is seven days wide. I figured that I'd share my class, since I'm probably not the first or last person to ever want to do this. Note that it's not finished...you'll need to add the last few days when the end of the month doesn't fall on Saturday, but that's not rocket science.
package com.magnoliamultimedia.vo
{
import mx.collections.ArrayCollection;
public class DisplayMonth
{
private var _year:int;
private var _month:int;
private var _startIndex:int;
private var _dateColl:ArrayCollection;
public function DisplayMonth(monthNumber:int, yearNumber:int)
{
_month=monthNumber;
_year=yearNumber;
var tmpArray:Array=new Array();
var firstDay:Date=new Date(yearNumber, monthNumber);
var lastDay:Date=new Date(yearNumber, monthNumber +1, 0);
var lastDayNum:int = lastDay.date;
_startIndex = firstDay.day;
var tempDay:Date;
var i:int;
//fill blank days before beginning of month
for (i=0; i<_startindex; i++)
tempday = new Date(yearNumber, monthNumber);
tempday.date -= 6-i;
tmpArray.push(tempday);
}
//fill in the rest of the dates here...
}
}
}
Sorry about the crap formatting...I haven't figured out the spiffy scrolling thing some other bloggers manage.
Updated 5/28/10. I noticed that part of the code had been "eaten" by Blogger. I replaced the relevant code, but may not have put back everything that was once there. For a better example of how to do this, look at my GroupingCollection example.
Posted by Amy B at 4:24 PM 2 comments
Labels: Actionscript, ArrayCollection, Date, flex, TileList, Value Object
Is the HorizontalList faster than an HBox with a Repeater?
english mobileThe Help files that come with Flex Builder claim that the HorizontalList control can have better performance than a HBox with a repeater:
"...performance of a HorizontalList control can be better than the combination of an HBox container and a Repeater object because the HorizontalList control only instantiates the objects that fit in its display area."
The truth is, this statement is false. The HorizontalList always instantiates one more control than is drawn in the display area. This extra component is created simply for measurement purposes and is kept in memory in case extra measurements need to be done. That's highly ironic, as I'll get to in a moment.
In a situation where the number of items does not exceed the area available, the HBox with a repeater component will instantiate exactly the number of renderers as items in your dataprovider, whereas the HorizontalList will instantiate one more. If your itemRenderers are heavy (for instance, if they themselves have a component that takes an itemRenderer), this difference can be significant. Additionally, Repeaters do offer the ability to recycle their renderers, which offsets most of the performance advantage you might get from a HorizontalList.
The second problem with the way the HorizontalList "does business" is more significant. If you have to use callLater to do anything that affects the size of the itemRenderers, the HorizontalList has already measured the component before the call that changes the size, and so the space it allocates to the renderer will not be the actual size of the renderer. And there doesn't appear to be any way to dispatch any events from the renderer or set any variables or call any methods that will convince the HorizontalList to use that extra, useless itemRenderer that is hanging around at the new and improved size to update the size.
Possibly you could subclass HorizontalList to make this work correctly, but why would you, since the HBox with an ItemRenderer just works?
Updated May 19: Today, I discovered that the HorizontalList doesn't always draw this extra renderer. If you specify a rowHeight, this step will be skipped.
Updated September 11, 2008: I think if I'd overridden measure() in my itemRenderer to explicitly report the size after the dataProvider was set in commitProperties, I could have gotten a HorizontalList to work. I later had a similar problem with a regular List, and overriding measure() fixed it.
Posted by Amy B at 8:01 AM 0 comments
Labels: CallLater, flex, HBox, HorizontalList, ItemRenderer, Repeater
eLearning Guild Online Forum on Flex
english mobileThe eLearning Guild does online forums from time to time that are like conferences that you attend from the comfort of your home or office. I am very excited that my first conference presentation on Flex will be at their online forum Selecting, Combining, and Using Authoring Tools. I will be presenting on strategies for migrating from Authorware to Flex.
Hope to see you there!
Importing Packages in AS3
english mobileEven the most simple task seems to take me forever in Flex, since I have to troll through reams of documentation to make sure I understand the concepts involved. This morning I came across something in one of my references that went something like this:
I went through reams of documentation looking for something to verify this, but couldn't. Finally, someone on a Google Group I belong to posted this quote from Colin Moock's Essential Actionscript 3.0."Because this class is in the same package as the other class you want to use, you don't need to add an import statement in order to use it."
"Code in a given package can refer to the classes in that package by their unqualified names... To gain access to a class in another package, we use the import directive..."
So yes, it's true. You don't have to import classes in the same package as the one where you are working.
Easy when you know how
english mobileI think I spent a couple of hours yesterday scouring the Flex docs to figure out how to make a tab on a TabNavigator disabled. And it seems like I'm not the only one. After messing with it for a while, I decided to set the enabled property on the child form to false. Which worked.
I went back to the docs and discovered that it had been there all the time:
If you disable a child of a TabNavigator container by setting its enabled property to false, you also disable the associated tab.
Weird, because I know I searched the TabNavigator help page for the word "disable" like a million times.
Comparing XML nodes of the same name with E4X
english mobileI recently found a situation that the Flex E4X documentation didn't cover, and I couldn't find an example for ActionScript 3 or JavaScript that covered it. Essentially, I had XML in the data property of an itemRenderer that looked something like this:
<question id="1>
<selected>
1
</selected>
<selected>
5
</selected>
</question>
Essentially, my itemRenderer has five buttons (A-E), any or all of which can be selected. If the user clicks one of the buttons and it is already selected, it should be deselected. Or, in other words, if there is already an element in the data XML's "selected" collection with the same value as what the user clicked (assuming A=1 and E=5), then that element should be deleted.
I had a challenge, though, in that I didn't want to use a for loop. I was using XML, and E4X should be able to handle this easily. The problem I had was that every E4X example I found that referenced the contents of the nodes of an XML node presumed that there would only be one of each node of the same node. So if my XML structure had been
<question id="1>
<selected>
1
</selected>
</question>
then life would have been easy. I could have used data.(selected==userSelection) and away I'd go. But the problem when you have multiple nodes named "selected" is that data.selected returns an XMLList that contains all of the nodes. Hence, it cannot be equal to any single number, even though when there is only one node it works fine.
So, after much research, I came up with something like this:
myXMLNode:XML="<selected>"+userSelection+"</selected>";
if (data.selected.contains(myXMLNode){
//loop through and delete any nodes with that value
} else {
//add a node of that value
}
I wasn't really happy with this, and I posted to the Flex Coders mailing list. Tracy Spratt suggested that I use the text() method of the XML object, so I wound up with something like this in my final logic:
if (data.selected.(text()==userSelection).length()==0){
//add the selected node to the data object
data.prependChild(myXMLNode);
} else {
//remove the selected node from the data object
for (i=data.selected.length()-1; i>=0; i--){
if (data.selected[i] == userSelection){
delete data.selected[i];
}
I hope this will help someone else solve this problem without having to waste as much time as I spent on this!
Debugger and E4X
english mobileI had a thingie that I had built in Flex, and I wanted to change it from showing a property of the xml object passed in the data object to the itemRenderer to iterating through child nodes of the xml object to show multiple selections. I thought my problem was with the E4X expression, so I wanted to be able to quickly change the E4X syntax without having to recompile and run my project again. So I decided I'd create a watch expression with my E4X in it and just keep trying until I got it right.
It seemed that no matter what I tried, I kept getting "Errors in Evaluation" for my E4X expression. Finally, in frustration, I put my best guess at the E4X expression in a trace expression, and it worked like a charm. The actual problem was that the logic wasn't even going into the piece I thought it was. So let that be a lesson to me that the debugger expressions window can't actually evaluate E4X!
Oh, and if anyone knows something in the debugger that works like the Immediate pane in VBA, please let me know!
Flex Debugging Tutorial
english mobileWhen I first picked up Flex, I couldn't make heads or tails of the debugger, so finding and fixing problems took forever. I looked everywhere to try to find some documentation on how to use this thing. I finally figured it out on my own, but I've finally found a tutorial on the debugger that will hopefully help other new Flex users from sharing my pain.