Introducing MinimalConfigurator

Jan 18 2011 Published by under Components

This is a concept I’ve had for a while, and last week started to implement it. It wound up being orders of magnitude simpler than I imagined. The core part of it was done days ago. I cleaned things up more recently and finally checked it in and made some examples. As easy as Minimal Comps are to instantiate and set up, once you start getting into more complex layouts with lots of components, you can still wind up with a messy bunch of code. Well now you can create your layouts in an external xml file and leave your classes to handle the logic, as it should be.

The concept is to load an XML file, similar to MXML (you can call it MCML if you need a name for it), that defines what components are to be instantiated, and all their properties. In keeping with the minimal theme, it’s not as hard core as something like MXML. You won’t find data binding or in line ActionScript, or styles, etc. And ALL properties are expressed as attributes, not nested tags. But I am happy to say I worked out some pretty neat things that I originally thought would be more difficult.

One is that a component that has an id attribute will be mapped to a public variable in the parent container if such a variable exists, so you can code things around these created components. For example public var btn:PushButton; will map to < PushButton id="btn"/>.

Second is that you can nest components for those components that can have children. Some components, such as Window, Panel, ScrollPane, expect children to be added to a content property, while others, such as VBox and HBox are added directly. These are both handled correctly. So you can write:

<comps>
    <Panel>
        <VBox x="10" y="10">
            <RadioButton label="one"/>
            <RadioButton label="two"/>
            <RadioButton label="three"/>
        </VBox>
    </Panel>
</comps>

And finally, you can assign events with the syntax: event=”eventName:eventHandler”. For example:

<PushButton label="Click me" event="click:onClick"/>

This assumes that the main container class has a public method called onClick that has the signature compatible with the event that will be dispatched. If it does not, the event handler will not be assigned.

You instantiate the class like so:

var config:MinimalConfigurator = new MinimalConfigurator(this);

You pass in the DisplayObjectContainer that the components will be added to. This is also where it will look for public ids and event handlers.

Then you can parse the xml in one of 3 ways:

// 1. load the xml from a url:
config.loadXML(urlString);

// 2. parse a string containing xml:
config.parseXMLString(xmlString);

// 3. parse an xml object:
config.parseXML(xml);

You can listen for an Event.COMPLETE event which will be fired when the xml is parsed and all the components are instantiated. This is mostly useful when loading the xml from a file, as that is asynchronous, obviously, though the rest are synchronous.

Here, you can try it out for yourself. Write some xml in the text field below and press “Parse XML” and it should create the components above.

Get Adobe Flash player

Here are a few examples to try, you’ll get the idea soon enough.

One:

<comps>
    <HBox x="10" y="10">
        <PushButton label="File" width="60"/>
        <PushButton label="Edit" width="60"/>
        <PushButton label="View" width="60"/>
        <PushButton label="Settings" width="60"/>
        <PushButton label="Help" width="60"/>
    </HBox>
</comps>

Two:

<comps>
    <Panel x="10" y="10" width="200" height="200">
        <HBox x="10" y="10">
            <VBox>
                <Label text="First Name:"/>
                <Label text="Last Name:"/>
                <Label text="Address:"/>
                <Label text="City:"/>
            </VBox>
            <VBox spacing="7">
                <InputText />
                <InputText />
                <InputText />
                <InputText />
            </VBox>
        </HBox>
    </Panel>
</comps>

Three:

<comps>
    <Calendar x="10" y="10"/>
    <HUISlider x="10" y="200" label="Amount"/>
    <HBox x="10" y="230">
        <Label text="Color:"/>
        <ColorChooser usePopup="true"/>
    </HBox>
    <IndicatorLight x="200" y="10" label="Warning" isLit="true"/>
    <IndicatorLight x="200" y="30" label="No Warning" isLit="false"/>
    <IndicatorLight x="200" y="50" label="Safe" color="0x00ff00" isLit="true"/>
</comps>

Finally, here’s a code example that shows how to use ids and events:

package
{
	import com.bit101.components.Component;
	import com.bit101.components.Label;
	import com.bit101.utils.MinimalConfigurator;
	
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	
	public class MinConfigTest extends Sprite
	{
		public var myLabel:Label;
		
		public function MinConfigTest()
		{
			Component.initStage(stage);
			
			var xml:XML = <comps>
							<Label id="myLabel" x="10" y="10" text="waiting..."/>
							<PushButton x="10" y="40" label="click me" event="click:onClick"/>
						  </comps>;
			
			var config:MinimalConfigurator = new MinimalConfigurator(this);
			config.parseXML(xml);
			
		}
		
		public function onClick(event:MouseEvent):void
		{
			myLabel.text = "You did it";
		}
	}
}

There’s a public var “myLabel” of type Label. This will be assigned the Label created in the first component tag, with the same id.

Then there’s a public method “onClick”. This is mapped to the button’s click event, so it will be called as an event handler when the button is clicked.

Pretty straightforward I think.

Obviously there are some more complex actions that will still need to be done with code, such as assigning list and combobox items, probably accordions, etc. But this should handle a good bunch of use cases.

The code is currently checked in and there’s a new SWC and zip available for download at the Google Code site. The class is com.bit101.utils.MinimalConfigurator. Enjoy.

Oh, and by the way, even if you aren’t interested in the new class, there are a few fixes in this build which might make it worth updating to anyway: Change Log.

19 responses so far. Comments will be closed after post is one year old.

  • Wow, this is awesome! I like the simple syntax, the variable/event bindings, and that the class is only ~200 lines so it’s sure to not bloat up the library. Can’t wait to give it a try. Thanks!

    • keith says:

      Thanks. Most of the work was actually in simplifying it from my original concept. I think I spent more time removing code than writing it. 🙂

  • felix says:

    dude you just built Flex.

  • keith says:

    Funny thing I just realized is that there were no changes to the components themselves to enable this. All it really is is simple xml deserialization.

    I think my next step will be to reverse the process and serialize them. Then I can build a better, more maintainable version of the Minimal Designer I did a while back.

  • JTtheGeek says:

    Looks absolutely great! Two questions: support for percentage widths/heights, and is the xml deserialization / class configuration cached in a way that the performance impact is minimal for creating a lot of components? I’m looking at building a charting library to replace Axiis, and I’m struggling to meet my needs of flexibility and performance, but this seems like a great way to achieve both.
    ~ JT

    • keith says:

      JT, there’s no support for percentage sizes, as that’s not part of the components themselves. Again, this is merely deserializing properties that already exist. No other calculations are done. I’m not sure what kind of caching you are looking for, but the answer is no in any case. But it’s all open source, so feel free to expand it to your needs.

  • Daniel says:

    I was wondering if you thought about linking the data to variables.
    This might take some working in with some of the individual components, but it would be nice if you could add an attribute like linkVar=”$day[ddmmyy]” to the calendar and be able to reference it through $form.$day.

    Anyway, I’m sure this is outside of the scope, but would make putting input controls together easier.

  • Justin says:

    Great stuff! Much better solution to mine. Looks like we were tinkering with this at exactly the same time. I’d say something about ‘great minds’ but wouldn’t want to imply that I’m up at your level! Look forward to playing around with it.

    Keep up the good work.

  • Sander says:

    Thanks Keith! Something tells me I will use this a lot.

  • Karim says:

    Working with this class now – it’s very useful thank you ! Makes the interface layout much easier.

    I’ve added a little function to the MinimalConfigurator; ‘getComponentByName( name : String ) : Component’ which lets you get any component you have added a ‘name’ property for. Useful for directly referencing nested components, although it’s not the nicest code. Here is my updated class;

    http://kurst.co.uk/transfer/MinimalConfigurator.as

    Also,

    having some issues figuring out how to use the Accordion with MinimalConfiurator. Am trying to add windows and content – if you have a case / example for that component it would be very nice to see it.

    Again, thanks for the Minimal Comps….

    • keith says:

      I like it. I originally had an idMap in there, similar to what you are doing, but wasn’t using it for anything, so removed it. Maybe I’ll add it back in with a getCompById method, and maybe combine id and name.

      As for accordions, check my 3rd to last paragraph in the post. I didn’t try, but didn’t expect it to work with them. You can create the accordion, size it, position it, etc. but you’ll have to manage the windows with code.

  • Joe says:

    There is a problem when you set value with the attibutes order.

    this make a slider with value 600 :
    HUISlider id=”hwidth” label=”width” width=”200″ labelPrecision=”0″ minimum=”-1″ maximum=”800″ value=”600″/

    but this make a slider with value 100 :
    HUISlider id=”hwidth” label=”width” width=”200″ value=”600″ labelPrecision=”0″ minimum=”-1″ maximum=”800″/

    I think the attibute value must be check at the end, not in the order of a forEach/for loop.

    🙂

  • Keith, you should take a look at this post, http://dgrigg.com/blog/2010/04/12/when-flex-goes-on-a-slimfast-diet/

    You can do almost exactly what you are after with pure MXML without the Flex framework overhead. I was blown away when I first ran across the idea. It works great with MinimalComps, which was the actual impetus for me, I got tired of writing out AS3 for complex layouts.

  • Matt Perkins says:

    This is really cool – and timely that you wrote it! I need something very similar for a current project.

    I’d had a similar system for a set of my components but it was messy factory, now this will make it really clean.

  • Mac Catt says:

    How would you implement a List, or ComboBox is this way…. the array thats passed to the constructor?

    Regards

    Great work

    Mac

  • Jens Eckervogt says:

    Wow, great component / frameworks 🙂

    I see like JavaFX. Great idea!

    I don’t believe because MinimalComponents will get better than Java FX 😀
    Thanks i would like to improve your old library into new version and would like to work support with Adobe Air and MDM Zinc 4.0.18 😀