The 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.
Working with Dates in AS3
english mobile
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!
