return undefined;


flexmdi: Customizing default behaviors

Posted in AS3, Flex, flexmdi by Ben on the September 14th, 2007

flexmdi handles a lot of the mundane tasks of an MDI interface for you: minimizing, maximizing, closing, etc. However, we also realize that the out of the box behavior will not always fit your exact needs. Consequently, one of our biggest architectural goals (and challenges) was how to provide enough default behavior that getting up and running was lightning fast while still allowing the fine grained control a truly useful project provides. I described the basic method we used in a previous post, but wanted to give an example more specific to flexmdi now that its live.

The example we always thought of during development was requiring a user to confirm that they want to close a window before it is actually removed, like this (view source enabled). Any listeners you set on MDIWindow or MDIManager will be called before the internal listeners that execute the default behavior. As long as you don't give your listener a negative priority that is, so don't do that if you want first dibs. To prevent the default behavior from executing, you simply call event.stopImmediatePropagation() on the event passed into your listener. If you might want to execute that default behavior in the future, such as after the user confirms they want to close the window, you need to store the event somewhere. Let's look at some sample code (assumes you're listening on the manager in order to catch events for all of the windows):

private function confirmWindowClose(event:Event):void
{
    if(event is MDIManagerEvent)
    {
        // this is the line that prevents the default behavior from executing as usual
        event.stopImmediatePropagation();
        // store the event in case we want to resume later (user confirms their intention)
        queuedEvent = event as MDIManagerEvent;
        // ask user to confirm
        Alert.show("Seriously? Close it?", null, 3, null, handleAlertResponse);
    }
}

So now we have captured the event, put it off to the side and prompted the user to make sure they really really really want to close the window. handleAlertResponse() will be called when the user clicks on one of the buttons provided by our Alert. Here is what that method looks like:

// if the user said yes, we execute the default behavior of playing an effect
// and then removing the window by calling the appropriately named executeDefaultBehavior() method
private function handleAlertResponse(event:CloseEvent):void
{
    if(event.detail == mx.controls.Alert.YES)
    {
        mdiCanvas.windowManager.executeDefaultBehavior(queuedEvent);
    }
}

As you can see, if the user told us to do so we go ahead and "resume" the default behavior (playing an effect and removing the window) by calling MDIManager.executeDefaultBehavior() and passing it the event we previously stored. Thats it. You now have an MDI interface that requires confirmation when closing windows.

Because executeDefaultBehavior() contains a switch that examines the event's type, you can use this exact approach to prevent and/or modify default behaviors for any event flexmdi uses. I think confirming window close would definitely be the most common usage, but I'm sure its not the only one. For example, you could intercept the windowMaximize event and fade all other windows back or minimize all other windows before animating the window to its maximized size/position.

As always, questions, comments, complaints, etc are welcome. I would love to get feedback on this and hear if you think its easy enough/will suit your needs/could be improved/will end world hunger.

flexmdi: Starting out simple with MDICanvas

Posted in Flex, flexmdi by Ben on the September 11th, 2007

The quickest, dirtiest, most basic way to use flexmdi is with the MDICanvas class. MDICanvas essentially wraps the manager (MDIManager) and container (Canvas) into one class, allowing you to define a basic MDI interface purely in MXML. Let's look at some code.

<flexmdi:MDICanvas id="mdic" width="500" height="500">
    <flexmdi:MDIWindow id="win1" title="Window One" x="10" y="10">
        <samples:SampleContent />
    </flexmdi:MDIWindow>
    <flexmdi:MDIWindow id="win2" title="Window Two" x="250" y="250">
        <samples:SampleContent />
    </flexmdi:MDIWindow>
    <flexmdi:MDIWindow id="win3" title="Window Three" x="100" y="100">
        <samples:SampleContent />
    </flexmdi:MDIWindow>
</flexmdi:MDICanvas>

As you can probably guess, this will create a 500 x 500 Canvas with three windows in it. The windows are created at the coordinates specified in the MXML, and since no size is specified they are created at the default size of 200 x 200.

As it turns out, thats pretty much all there is to it. You could also use this approach for doing a quick layout in MXML but still use AS to gain a little more control and customize things. You can obviously address any of the windows by their id, but you can also address the MDIManager that is created for you with code like this: mdic.windowManager. I will discuss some of the more advanced topics in subsequent articles but feel free to leave questions or comments.

Announcing flexmdi: Robust, extensible MDI framework for Adobe Flex

Posted in AS3, Flex, flexmdi by Ben on the September 11th, 2007

One thing the Flex community has lacked up to this point is a robust, extensible, open source solution for creating MDI interfaces. Today that is changing as myself (Ben Clinkinbeard), Brian Holmes and Brendan Meutzner are excited to announce flexmdi. As the name and my introduction implies, flexmdi is a framework for easily creating MDI interfaces in Adobe Flex. While you can literally get up and running with flexmdi in a matter of seconds, our team focused heavily on allowing developers to easily extend and customize the framework to fit it to their specific needs.

The project has been constructed during nights and weekends over the past month or so since we all have day jobs, but the focus has always been on creating a framework that enables developers to be productive out of the gate while allowing powerful customizations by way of an intuitive and robust API. Some highlights include:

  • Draggable, resizable (from any edge/corner) windows
  • Default functionality for minimize, maximize/restore and close
  • Extensive event model on both a window and manager level
  • Externalized effects classes for transitions (allows developers to create their own or extend from our base implementations)
  • Cascade, tile and tile plus fill space window management
  • Context menu functionality
  • Ability to modify/customize default behaviors, not just override them (though you can do that too)
  • Construct UIs in MXML or AS

We have a few articles/tutorials put together already, and more are on the way. This is a pretty solid 1.0 release, but we will also be polishing and cleaning things between now and MAX, where we will be giving a short demo during the Flex Boot Camp session. Please send us your feedback! We are eager to hear from other developers about what is good, what is bad, what should be easier, what use cases you would like support for, etc, etc.

So now, onto the links:

Thats all for now, but expect ongoing updates and articles. And once again, got a complaint? Tell us! Like what you see? Tell us! Want to contribute (code, not money) to the project? Tell us!

Enjoy!

PS - Quick shout out to Wietse Veenstra. We used his stylesheet as a starting point and I believe are still using his images for the window controls buttons. Thanks!

Custom Flex components: Providing default yet overridable behavior

Posted in AS3, Flex by Ben on the September 7th, 2007

A good component provides enough out-of-the-box capability that getting up and running with it is quick and easy. An even better component allows for the flexibility of overriding and/or customizing that default behavior. As it turns out, providing this flexibility in your components is quite easy. This article will explain how to do just that.

Since Flex uses an event based programming model, the addEventListener() method is one of the foundational aspects of Flex development. The fourth parameter of this method is priority. What this does is allow developers to "rank" their listeners and specify in which order they should be executed. Listeners are called in descending order, so a listener with a priority of 2 will be called before a listener with a priority of 1, which will be called before a 0 priority listener, etc. It should be noted, however, that listeners will not necessarily finish executing before the next one in the queue is called. The default priority is 0, as evidenced by addEventListener()'s signature:

addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void

The priority argument is the key to providing default yet overridable/customizable behavior in your custom components. The basic approach, in a nutshell, is to have your component listen for its own events, but with a priority of -1 (or any negative number, really). By doing this, you let users of your component (other developers) listen for the events externally as normal, but also give them the option of preventing the event from ever reaching your default internal listeners. The Event class provides a stopImmediatePropagation() method that prevents the event from being dispatched to any listeners with a lower priority. So if you add a listener with the default priority of 0 (or any positive number) and call event.stopImmediatePropagation(), the event will never reach the default internal listener, since it has a negative priority.

Here is an example, with view source enabled. The project that necessitated figuring this stuff out will hopefully be going live early next week, so stay tuned. :)

Update: The project is live!