Posted by: edsyrett | 2 January 2011

2010 in review

The stats helper monkeys at WordPress.com mulled over how this blog did in 2010, and here’s a high level summary of its overall blog health:

Healthy blog!

The Blog-Health-o-Meter™ reads Fresher than ever.

Crunchy numbers

Featured image

A Boeing 747-400 passenger jet can hold 416 passengers. This blog was viewed about 12,000 times in 2010. That’s about 29 full 747s.

 

In 2010, there were 3 new posts, growing the total archive of this blog to 46 posts. There were 7 pictures uploaded, taking up a total of 1mb.

The busiest day of the year was March 23rd with 92 views. The most popular post that day was Focus Loops within Focus Loops.

 

Where did they come from?

The top referring sites in 2010 were riacodes.com, flexer.info, whatsmytitletoday.blogspot.com, cookbooks.adobe.com, and mysearchitnow.com.

Some visitors came searching, mostly for flex sliding panel, flex slide panel, flex xml remove child, flex multi column form, and sliding panel flex.

Attractions in 2010

These are the posts and pages that got the most views in 2010.

1

Focus Loops within Focus Loops November 2009
8 comments

2

Focus issues in Flex August 2008
8 comments

3

Sliding Panel May 2009
5 comments

4

Multi-column forms February 2009
3 comments

5

Industrial-strength builds with Flex July 2008
2 comments

Posted by: edsyrett | 23 October 2010

Multi-type Item Editor

We’re all familiar with the way renderers and editors work in grids ok? You set a renderer and/or editor for a column and it all just works.

But what happens if you need to change the way an editor works based on the content of a line?

That’s the requirement I had recently. I have lines in a grid where I want the column to show a list of possible values, and some lines where that column shouldn’t be edited at all. This all has to work with the limitation that a DataGridColumn will only allow you to have one item editor.

So I had to create an item editor that changes it’s functionality based on the data it gets.  It’s actually not that difficult – it’s just a canvas with two child controls – a TextInput and and a ComboBox.

I had to solve the problem of how to get the items into the ComboBox.  My solution was simply to add it to the data for the grid:

private var gridData:XML = <rows> <row type="TEXT" value="This is text"/> <row type="LIST" value="Item Two"> <listdata> <item id="1" label="Item One"/> <item id="2" label="Item Two"/> <item id="3" label="Item Three"/> </listdata> </row> <row type="NONE" value="This cannot be edited."/> </rows>

My test app simply looks for specific elements in the XML to populate the combo, but you could enhance this by telling the renderer which elements to look for etc. This would actually become a necessity if you needed more than one multi-type editor on a grid line.

Also I have added a custom ComboItemEditor component that uses a minimal skin – using a standard combo here just looked ugly due to the border with rounded corners.

Lastly, you’ll see that the last item in the list has a type of “NONE”, which should prevent any editing at all in cells using the multi-type item editor. For my test app, I have just added a handler for the itemEditBegin event that checks the data for that line and prevents editing.

private function onItemEditBegin(event:DataGridEvent):void { if (event.itemRenderer.data.@type == "NONE") event.preventDefault(); }

Right now, this will prevent any editing on the line, but if you only need to prevent editing on columns where you’re using the multi-type editor, you will need to check which column is being edited.

Click on the screenshot above to check out my test app. The usual caveats apply.

Posted by: edsyrett | 8 April 2010

What’s happening?

Just in case you get here and wonder why I haven’t posted anything for a couple of months, it’s because we’re stopping doing Flex.

Our problem with Flex is that you can’t run Flex apps in a browser and host the whole thing in Citrix – the browser and Flex combination takes up way too much memory.

Ok, so you’re asking “why are you running Flex apps in Citrix”? Well, it’s because we are a global Logistics company and a lot of our offices have WinTerms (very small PCs) that just run a Citrix client. That way, our operations staff just have the Citrix servers to manage, not loads of PCs on desks.

Also, we want to write one app that can be run either via Citrix, or over the web.

So we are looking at Google Web Toolkit instead. It takes up less memory in the browser, which will hopefully allow us to run more realistic numbers of clients on a given Citrix server. And of course it can run over the web.

So there probably won’t be any more from me on Flex. Maybe I had better change the name of the Blog from Flexibility to something else….any suggestions?

Posted by: edsyrett | 22 January 2010

Logging debug messages to FireBug Console

FireBug is a very handy add-on for FireFox – you can find out more about it here.

In addition, FireBug provides a way of logging messages – see here.

Firebug adds a global variable named “console” to all web pages loaded in Firefox. This object contains many methods that allow you to write to the Firebug console to expose information that is flowing through your scripts.

So far, this is all for JavaScript debugging.  But don’t forget the ExternalInterface in Flex.  So we can call these methods just as easily from inside a Flex application as fron JavaScript.   Here’s one way to do it:

package utils { import flash.external.ExternalInterface; public class Console { public function Console() { } public static function log(message:String):void { ExternalInterface.call("console.log", message); } } }

And to log a message…

Console.log("Put your message here...");
Posted by: edsyrett | 11 December 2009

Sorting XML in AdvancedDataGrid

If you use native types in the dataprovider of an AdvancedDataGrid, the grid will look at the first row of data to figure out how to sort the columns.  For example if you have set the datafield of the first column to reference numeric data, the column will be sorted numerically.  In other words, 100 will appear after 2 etc.  Similarly for dates.

However, if you pass XML data, none of this will work – all the text in the elements and attribute are by definition text, and no code in the world can look at the data and reliably decide whether to sort as text, numbers or dates.

After having a look at the framework code, it became quite easy to see where extra functionality was needed.  Click on the screenshot of the grid above and you’ll see my app that has XML data but is correctly sorting a numeric and date field.

I have monkey-patched the initCompare() function of SortField to look for additional attributes in the XML which define what the sort should be.  The code for each column looks at the datafield for the column, and then looks for an additional attribute with the extension “_format”.  In otherwords, if your grid column has a datafield “total”, the new code in SortField looks for an attribute with the name “total_format”.  The value of this extra field can be “string”, “numeric” or “date” and the new code will put in place the correct sort function.

Posted by: edsyrett | 27 November 2009

Focus Loops within Focus Loops

Some time back I created my Sliding Panel component and did a demo of it here.

The problem with this component as it stands is that the focus goes around all the focusable components, including those on the sliding panel.  In other words, you can tab around the TextInput controls on the main forms, and then focus will disappear off onto the TextInput controls on the sliding panel, even if it’s closed.  What is really required is a separate focus loop around the components in the sliding panel.

I started off just by creating a new instance of FocusManager and pointing it at the SlidingPanel instance.  That solution suffered from two problems:

  • Firstly whilst focus would correctly move around all the components within the sliding panel, focus in the parent form would also include the components in the panel.   This wasn’t really a surprise as the FocusManager in the parent form will just go right ahead and include all the focusable component that it finds in its children, which will include those in the sliding panel.
  • Secondly, I hit a big bug in SystemManager.  I just clicked on a TextInput in the sliding panel and the app crashed in SystemManager::mouseDownHandler(), on the line:
index = childList.getChildIndex(p);

The code in SystemManager assumes that all the members of the forms collection are either pop-ups or direct children of the SystemManager instance.  My new FocusManager automatically added itself to the forms collection, but it was somewhere in the middle of the display list, not a pop-up of child of the SystemManager.  So I had to fix this issue, and for now I’ve just put that whole section of code in a try/catch block so that it survives the call to childList.getChildIndex(p).

The next problem to solve was that focus in the main form continued around all the controls in the sliding panel.  This was relatively easy to fix just by setting the tabChildren property of the SlidingPanel class to false.  This meant that the FocusManager handling the main form stopped adding any focusable components within the sliding panel.

However, this had a major side-effect – the FocusManager handling the components contained in the sliding panel didn’t work at all.  The reason was that in addFocusables() there was a call to isTabVisible() which searches up the display list to see if any parent objects have tabChildren set to false.  Of course, this spotted that SlidingPanel had its tabChildren property set to false and concluded that all its children should be ignored for tabbing.  So I had to create my own SlidingPanelFocusManager which didn’t perform that test.

The end result is here.  You can tab around the 6 TextInput controls and focus won’t enter any of the sliding panels.  If you open a panel, however, focus will move around the controls within the panel, including the button to open or close the panel.  It all works, but the number of changes to the mx framework mean that it won’t see production for a while until I make sure that there aren’t any more side effects.

Posted by: edsyrett | 20 November 2009

Custom Overlays and getting the scale

Custom Overlay and map scale

I needed to create a map with a movable circle on it, and then be able to hit a button and get a list of locations within that circle.

This presented a couple of problems – firstly how to draw a circle over the top of the map, and secondly, how big to make it.   Looking at the map API, there’s not an easy way to figure out what the scale of the map is.  In other words, you have to find out how many pixels wide the circle needs to be to represent a given radius in kilometres on the map, taking into account the current zoom level.

Here’s how I did it….

private function calculateMapScale():Number { var topLeft:LatLng; var bottomLeft:LatLng; var scale:Number; var distance:Number; topLeft = _mapPane.fromPaneCoordsToLatLng(new Point(0,0)); bottomLeft = _mapPane.fromPaneCoordsToLatLng(new Point(0, _map.height)); distance = topLeft.distanceFrom(bottomLeft) / 1000 ; scale = _map.height / distance; return scale; }

All the code above does is get the top and bottom of the map as lat/longs and then find the distance between the two points. Then I have the number of pixels and the distance they represent.

And the caveats are:

  • This relies on the use of one of the later versions of the API library – you need to set applyProjection to true on the GroundOverlayOptions otherwise you’ll get an oval instead of a circle.
  • I just get the vertical scale, and assume that the horizontal scale is the same.

Click on the image to get to my prototype app. The app includes a slider with a range of 0 to 10000 to set the radius in kilometres of the circle. The circle itself just moves automatically to the centre of the map.

Posted by: edsyrett | 26 September 2009

Scaling an mx:Text – The Bottom Line…

Have a look at my little test app here.

On the numeric stepper, keep increasing the scaling.

You’ll find at about 1.26, a strange thing happens – you lose the bottom line.

As usual in my adventures with the Flex SDK, it’s a bug.  But this time I don’t think it’s a bug in the Flex SDK.   I believe it is in the text control in Flash Player.

Anyway, there is a bug report, and it’s here: SDK-16876.

If you encounter this issue with showing controls on the screen, you can probably get around it by setting an explicit height on the Text control.  However, what happens if you want the Text control to grow it’s height?  Setting an explicit height simply isn’t going to work if you don’t know at runtime if the Text control will hold 2 lines or 20.

But there is another sting in the tail of this particular bug.  You may be able to work around this issue on the screen by either sizing components or not scaling them.  But there is one time where you will have to use scaling…..

Printing.

And that’s where I hit this problem.  I can’t use any of the existing solutions in my app because I need the Text control to grow to show all it’s text, and I need to print that Text component, so it needs to scale properly.

My test app uses a copy of the Text component, and I have updated it a bit.   I have added a new function:

private function getCalculatedTextHeight():Number { var textHeight:Number = 0; for(var i:int=0; i < textField.numLines; i++) { textHeight += textField.getLineMetrics(i).height; } // SDK-16876 // Comment in this line instead of the following one // to fix the issue. // return Math.ceil(textHeight) + 4; return Math.ceil(textHeight); }

It seems that there is a rounding error somewhere, because if you add 4 to the height returned by getCalculatedTextHeight(), the problem goes away. The downside is that Text controls appear a bit larger in height, but the major plus side is that all the lines in my Text controls now get printed.

I thank you.

Posted by: edsyrett | 25 August 2009

MAXwidget

Posted by: edsyrett | 18 August 2009

Loading assets on demand, and blowing up Flex Builder…

We’re using the Flash API for Google Maps.  You can specify your own image for a location marker, and because we don’t do anything by halves here, we wanted an image for each location.

So we generated 99 icons for 20 routes, with each route being a different colour, and the number embedded in the icon.  In fact, the background colours from the icons were generated using the colours from my Colour Scheme tool that I mentioned in my previous post.

So thats about 180 small images that we wanted to download to the client.  Rather than making each client download these images every time, we wanted the client to only download the images when they were required.  So the images are in their own swf which is simply a compiled stylesheet.  The stylesheet looks like this:


route1
{
drop1: Embed(source='../assets/drop_icons/1/drop_icons_1_1.png');
drop2: Embed(source='../assets/drop_icons/1/drop_icons_1_2.png');
drop3: Embed(source='../assets/drop_icons/1/drop_icons_1_3.png');
drop4: Embed(source='../assets/drop_icons/1/drop_icons_1_4.png');
drop5: Embed(source='../assets/drop_icons/1/drop_icons_1_5.png');
...etc...

I’ve named the styles according to how they are used, so that one style has all the icons for a single route.

Then I wrote a simple little app to make sure that I could get the images out and pass them to the map API.  You can click on the image at the top of this post to go to the test app – View Source is enabled, but you won’t get the images cos we had to pay for those…:-D

And then there was the problem of Flex Builder just exiting without warning. I found that after I had built the swf containing these 180 images, I would continue normally for a couple of minutes and then I performed some action like opening a project, and Flex Builder would just vanish. It exited. It was no more. A few very strange messages were produce, and reading between the lines it seems that Flex Builder just ran out of memory.

Flex Builder is working ok up to a point in that it managed to compile the swf.  However, there’s obviously something not being tidied up after the compilation, so I have raised a bug with Adobe and it’s here.  I’m pleased that it seems to be getting quite a bit of attention from the Adobe guys….

Older Posts »

Categories