Author Archive for eric

The BetterTitleWindow Component: A better way to customize title bars

It's pretty common to need to put a button or some other component into the title bar of a Panel or TitleWindow component (I'm going to refer to both of these components as Panel components since they are nearly the same). The Flex Panel components don't provide any support for this, but it can be done by subclassing, overriding the createChildren method, and adding code to insert components into the titleBar UIComponent. (This technique is explained here and many other places.)

But it seems silly to have to create a new subclass for each different button or other component that you need to add to a panel. And this basic technique doesn't allow you to make any modifications to the title bar on the fly. It recently occurred to me that it would be really handy if title bars were handled just like the ControlBar component--as a container tag that you can put inside your Panel and then everything inside of it will automatically be placed in the proper location at the top of the Panel.

So... I created the BetterTitleWindow component which does exactly that. Here's some mxml illustrating its usage:

It's pretty simple. Just put the TitleBar tag inside the BetterTitleWindow and add any components you need inside the TitleBar. TitleBar is nothing more than an HBox, so as you can see in the example, you can set all of the usual HBox padding and alignment styles for controlling its layout. The TitleBar instance is then accessible through the titleBarContainer property of BetterTitleWindow, so you can add more components or change styles or anything else at runtime. Here's a small sample app that demonstrates this capability:

You can also download the project from our svn repository.

Comment

The TreeBrowser Component: Mac OS X – style column view for Flex

I've always been a big fan of the column view in the Mac OS X Finder (and earlier on NeXT OS). It's a clear, intuitive way to navigate through hierarchical data, particularly when that data is nested many levels deep. For a while I've been wanting to create a generic Flex component to display data column-style, but I've never managed to set aside the time to do it... until now!

The TreeBrowser component can be used anywhere the standard Tree component can. Like Tree, it supports displaying data from xml and basic nested object stuctures by default, and you can set a custom data descriptor to display any other kind of complex data (more info on data descriptors can be found here). By default it uses the same folder and document icons as Tree, and style settings can be used to set custom icon classes. It also has iconFunction and iconField properties for setting icons on an object-by-object basis. Each column in the component is a standard Flex List, and the style of the columns can be set to customize their appearance.

The TreeBrowser can also optionally display a "details" pane that shows information about the currently selected leaf node of the tree. If enabled, the details pane defaults to a simple two column DataGrid displaying the name and value of each property of the selected object. A custom detailRenderer can be set to show information tailored to a particular kind of object or usage of the TreeBrowser.

Here's a source-enabled example showing usage of the TreeBrowser to navigate XML data. This example also uses the excellent flexmdi framework to demonstrate how TreeBrowser components behave when resized. The three buttons at the top will open windows with or without the details pane, or with a custom detailRenderer.

You can also download the project from our svn repository.

TreeBrowser API Documentation can be found here.

And be sure to let us know if you find any interesting uses for this component...

18 Comments

Basic Flex Chart Styling

Most of the Adobe-supplied Flex components are pretty straightforward to start using and to customize to your liking. Usually I just drop one in and then consult the Flex 3 Language Reference doc to see what properties and styles I need to use to tailor its appearance. When I started to use the charting components, however, things were not so simple. The default appearance for the charts is really (no offense Adobe) quite ugly, and didn't match the application I was developing at all, but looking at the reference guide it was hard to figure out how to make even the most basic style changes. All I really needed to do was change the color and thickness of a line chart's series lines, remove the drop shadows, make the vertical axis thinner, and change the colors axes, labels, and grid lines. But from looking at the list of properties and styles for a chart, I had no clue how to accomplish this. So my first tip: read the documentation. Not the reference doc, but the actual Flex Data Visualization Developer's guide. The table of contents is good and it's pretty easy to find the relevant sections for styling. The chapter on charting can be found here: http://livedocs.adobe.com/flex/3/html/Part1_charting_1.html

Here's a quick example. The image below is of a completely default LineChart component, placed on a dark grey background.

And here's the mxml that defines it.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="0x333333" backgroundGradientAlphas="0,0">
    <mx:Script>
        <![CDATA[
 
        import mx.collections.ArrayCollection;
 
        [Bindable]
        private var expensesAC:ArrayCollection = new ArrayCollection( [
            { Month: "Jan", Expenses: 1500, Amount: 450 },
            { Month: "Feb", Expenses: 200, Amount: 600 },
            { Month: "Mar", Expenses: 500, Amount: 300 },
            { Month: "Apr", Expenses: 1200, Amount: 900 },
            { Month: "May", Expenses: 575, Amount: 500 } ]);
        ]]>
    </mx:Script>
 
   <mx:LineChart id="linechart" height="300" width="500" x="100" y="100"
        dataProvider="{expensesAC}">
 
        <mx:horizontalAxis>
            <mx:CategoryAxis categoryField="Month"/>
        </mx:horizontalAxis>
 
        <mx:series>
            <mx:LineSeries yField="Expenses"/>
            <mx:LineSeries yField="Amount"/>
        </mx:series>
    </mx:LineChart>
</mx:Application>

Not so pretty. So here's the rundown on how I made the necessary styling changes:

  • Color and thickness of series lines - created stroke objects, assigned these to each line series
  • Label color - just set the color style on the chart itself
  • Removing drop shadows - set the seriesFilters property of the chart to an empty array
  • Color and thickness of axes - created stroke objects, assigned these to the the axis renderers inside the horizontalAxisRenderers and verticalAxisRenderers properties of the chart
  • Color of grid lines - assigned stroke to GridLines object inside backgroundElements property of the chart

Here's the result, after styling.

And here's the mxml for the styled version.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" backgroundColor="0x333333" backgroundGradientAlphas="0,0">
    <mx:Script>
        <![CDATA[
 
        import mx.collections.ArrayCollection;
 
        [Bindable]
        private var expensesAC:ArrayCollection = new ArrayCollection( [
            { Month: "Jan", Expenses: 1500, Amount: 450 },
            { Month: "Feb", Expenses: 200, Amount: 600 },
            { Month: "Mar", Expenses: 500, Amount: 300 },
            { Month: "Apr", Expenses: 1200, Amount: 900 },
            { Month: "May", Expenses: 575, Amount: 500 } ]);
        ]]>
    </mx:Script>
 
     <!-- Define custom Strokes. -->
    <mx:Stroke id="stroke1" color="#0099FF" weight="2"/>
    <mx:Stroke id="stroke2" color="#C0FDAC" weight="2"/>
	<mx:Stroke id="axisStroke" color="#FFFFFF" alpha=".2" weight="2"/>
	<mx:Stroke id="lineStroke" color="#FFFFFF" alpha=".2" weight="1"/>
 
	<!-- set color of labels -->
   <mx:LineChart id="linechart" color="#FFFFFF" height="300" width="500" x="100" y="100"
        dataProvider="{expensesAC}">
 
        <!-- turn off drop shadows -->
        <mx:seriesFilters>
        	<mx:Array/>
        </mx:seriesFilters>
 
        <!-- assign ids to axes -->    
        <mx:horizontalAxis>
            <mx:CategoryAxis id="xAxis" categoryField="Month"/>
        </mx:horizontalAxis>
 
        <mx:verticalAxis>
        	<mx:LinearAxis id="yAxis"/>
        </mx:verticalAxis>
 
        <!-- assign strokes to axis renderers -->
        <mx:horizontalAxisRenderers>
        	<mx:AxisRenderer axis="{xAxis}">
        		<mx:axisStroke>{axisStroke}</mx:axisStroke>
        		<mx:tickStroke>{axisStroke}</mx:tickStroke>
        		<mx:minorTickStroke>{axisStroke}</mx:minorTickStroke>
        	</mx:AxisRenderer>
        </mx:horizontalAxisRenderers>
 
        <mx:verticalAxisRenderers>
        	<mx:AxisRenderer axis="{yAxis}">
        		<mx:axisStroke>{axisStroke}</mx:axisStroke>
        		<mx:tickStroke>{axisStroke}</mx:tickStroke>
        		<mx:minorTickStroke>{axisStroke}</mx:minorTickStroke>
        	</mx:AxisRenderer>
        </mx:verticalAxisRenderers>
 
		<!-- assign strokes to line series -->
        <mx:series>
            <mx:LineSeries yField="Expenses" displayName="Expenses" lineStroke="{stroke1}"/>
            <mx:LineSeries yField="Amount" displayName="Amount" lineStroke="{stroke2}"/>
        </mx:series>
 
        <!-- assign stroke to grid lines -->
        <mx:backgroundElements>
			<mx:GridLines direction="horizontal">
				<mx:horizontalStroke>{lineStroke}</mx:horizontalStroke>
			</mx:GridLines>
        </mx:backgroundElements>
    </mx:LineChart>
</mx:Application>

Obviously, there's a lot more that could be done to really skin or style the chart, but at least this gets rid of the default look and lets the chart blend in a little more to a particular application.

Comments

Drag And Drop Markers Made Easy

While the basics of creating drag-and-drop functionality in Flex are easily implemented through the DragManager, there are some important details that aren't handled for you, especially if you are using custom components (as opposed to using the built-in list-based components). For example, it's often useful to display a visual indicator of where the object being dragged will be inserted when released. Here at 9mmedia we've needed to do this on several occasions for things like visual editing tools. To facilitate this, we created a simple container component called DragMarkerBox that provides the marker functionality for any objects that are dragged inside of it.

Working Example:
http://www.9mmedia.com/examples/dragmarkerexample
Get the code:
http://code.9mmedia.com/svn/public/DragMarkerExample

The basic usage of the component is extremely simple; since it extends the Box container class, you use in the same way you would an HBox or VBox. One slight catch is that the container needs to have a backgroundColor specified, otherwise too many mouse events get fired when dragging over the items in the DragMarkerBox and the marker will flicker and appear jittery.

	<dragmarkerbox:DragMarkerVBox id="leftMarkerBox" backgroundColor="#ffffff">
		<DragItem itemLabel="1"/>
		<DragItem itemLabel="2"/>
		<DragItem itemLabel="3"/>
		<DragItem itemLabel="4"/>
		<DragItem itemLabel="5"/>
	</dragmarkerbox:DragMarkerVBox>

Note that the DragMarkerbox container doesn't automatically make the objects it contains draggable; it's up to the objects themselves to call DragManager.doDrag and begin the drag operation. Once dragging has started, however, DragMarkerBox will track the mouse position in relation to the objects being dragged over and display a marker either before or after the object currently under the mouse. When the item is dropped, DragMarkerBox will dispatch a DragMarkerEvent containing the DragSource and the position where the drop occurred.

There is a default marker component included, but you can customize the appearance of the marker by specifying your own markerFactory.

If you want to restrict the objects that can be dropped inside of the DragMarkerBox, you can specify an acceptFunction that will be used to evaluate whether a dragged object should be accepted as a valid drag action. If the object is not accepted, the drag marker will not display, and no DragMarkerEvent will be dispatched on mouse release. The acceptFunction should be defined as a function that takes one argument (the object being dragged) and returns a boolean value.

That's pretty much all there is to using the component. It's simple, but can be used in some powerful ways. You can nest as many levels of these containers as you want, and mix horizontal and vertical orientations.

Comments