return undefined;


flexmdi sans MXML

Posted in AS3, Flex, flexmdi by Ben on the March 11th, 2008

Every now and then I come across a request of how to use FlexMDI using only ActionScript. Its completely straightforward but I have finally gotten around to getting an example up. The first code snippet shows how to do this while still utilizing MDICanvas for some of the convenience it provides.

import flexmdi.containers.MDICanvas;
import flexmdi.containers.MDIWindow;
import flexmdi.effects.effectsLib.MDIVistaEffects;

private function init():void
{
    var mdic:MDICanvas = new MDICanvas();
    mdic.percentWidth = mdic.percentHeight = 100;
    mdic.effects = new MDIVistaEffects();
   
    var win1:MDIWindow = new MDIWindow();
    win1.title = "First Window";
    win1.width = 300;
    win1.height = 200;
    mdic.addChild( win1 );
   
    var win2:MDIWindow = new MDIWindow();
    win2.title = "Second Window";
    win2.width = 300;
    win2.height = 200;
    win2.x = 325;
    win2.y = 50;
    mdic.addChild( win2 );

    var btn:Button = new Button();
    btn.label = "Awesome Button";
    win2.addChild( btn );
   
    addChild( mdic );
}

This next example shows how to turn a basic Canvas component into the container for an MDI implementation.

import flexmdi.containers.MDICanvas;
import flexmdi.containers.MDIWindow;
import flexmdi.effects.effectsLib.MDIVistaEffects;
import flexmdi.managers.MDIManager;

import mx.containers.Canvas;

private function init():void
{
    var canvas:Canvas = new Canvas()
    canvas.percentWidth = canvas.percentHeight = 100;
   
    var mgr:MDIManager = new MDIManager( canvas, new MDIVistaEffects() );
   
    var win1:MDIWindow = new MDIWindow();
    mgr.add( win1 );
    win1.title = "First Window";
    win1.width = 300;
    win1.height = 200;
    win1.x = win1.y = 10;
   
    var win2:MDIWindow = new MDIWindow();
    mgr.add( win2 );
    win2.title = "Second Window";
    win2.width = 300;
    win2.height = 200;
    win2.x = 350;
    win2.y = 100;

    var btn:Button = new Button();
    btn.label = "Awesome Button";
    win2.addChild( btn );
   
    addChild( canvas );
}

Hopefully this clears up some of the uncertainty around how to use FlexMDI without our good friend MXML but feel free to ask questions in the comments.

Feedback from my session at 360|Flex Atlanta

Posted in 360|Flex, Flex, flexmdi, pointless blather by Ben on the March 5th, 2008

Following Adam's lead, again, I thought I would post the link to the feedback provided by people who attended my session last week in Atlanta. Tom and John rock the transparency vibe pretty hard so I figure its fitting for the speakers to do the same. This was my first time presenting at a conference and overall I was pretty happy with the outcome. I think the feedback stating it focused on FlexMDI a bit too much is probably valid and I apologize for that. My intention was simply to use it as a vehicle to illustrate the concepts I was discussing, I didn't mean to showcase it in any way. I'd also like to repeat that I was/am not the only developer of FlexMDI. It was a joint effort between myself, Brian Holmes and Brendan Meutzner.

View the feedback

Thanks to everyone who attended, even if you didn't provide feedback! Though I really like those of you who did :)

My slides from 360|Flex Atlanta

Posted in 360|Flex, Flex, flexmdi by Ben on the February 26th, 2008

I have posted a PDF of the slides from my presentation earlier today. The topic was Creating Flexible Components for Reuse and Distribution and we covered some things to keep in mind when creating components that you want to use across different projects and/or release to the public. There was a really good turnout and the material seemed well received. These slides aren't very detailed because I am a big believer in minimal amounts of text on slides but I think there is enough to make them worth posting. I settled for PDF because the rest of Keynote's export options kind of suck and its late. I'm tired. If anyone wants to add them to something like SlideShare feel free to do so and send me the link.

flexmdi 1.1 release - Enhancements and bug fixes

Posted in Flex, flexmdi by Ben on the February 12th, 2008

I just uploaded a new ZIP file to the flexmdi site. This release contains both bug fixes and enhancements, though the additions may be somewhat transparent to a lot of users. I did a pretty bad job of tracking which issues I fixed and closed during this update, but I think there were at least 20 of them. There were a few issues around focus and z-order that were fixed, support for basic truncation of window titles was added, did some general refactoring and MDIManager has a new enforceBoundaries property that when set to false will allow windows to be dragged partially outside of their container. The default value is true and MDICanvas has the same property which just acts as a pass through for convenience.

Window Controls

The biggest changes, however, are around styling and the layout of window controls in the title bar. The MDIWindowControlsContainer class is now the default class responsible for laying out things like minimize, maximize and close buttons. You can create subclasses of this class and then assign them to windows via the windowControls property to give your windows a different appearance. To do basic modifications you simply override the updateDisplayList() method like in any other component and flexmdi handles the rest. You can also override createChildren() if you want a set of controls that differ from the defaults. MDIWindowControlsContainer extends LayoutContainer, so you can set the layout property to achieve either absolute, horizontal or vertical layouts. The default is a horizontal layout like HBox that positions itself on the right side of the titleBar. You can easily implement different layouts though and we've included a couple of them in the examples.

Check out the updated explorer and use the styles dropdown on the top right to see examples what kind of different layouts are now possible. The Windows XP style just uses a different horizontalGap than the default layout but the Mac OS 9 style is significantly different. To lend more power to the layout containers, I also exposed the titleTextField of the windows (via MDIWindow.getTitleTextField()) which is protected by default and the titleIconObject (via MDIWindow.getTitleIconObject()) which is mx_internal by default.

Styling

The other significant work was related to default styling of the windows and implementing a system to allow easy overriding of styles. MDIWindow now has a windowStyleName property that allows you to point it to a master style that will be applied to that window. That style then points to substyles to allow fine grained control over individual aspects of window styling. You can of course also override styles by setting values inline via MXML attributes. A master style might look something like this:

.customWindowStyle
{
    styleNameFocus: "myWindowFocus";
    styleNameNoFocus: "myWindowNoFocus";
   
    titleStyleName: "myTitleStyle";
   
    minimizeBtnStyleName: "myMinimizeBtn";
    maximizeBtnStyleName: "myMaximizeBtn";
    restoreBtnStyleName: "myRestoreBtn";               
    closeBtnStyleName: "myCloseBtn";
   
    windowControlsClass: ClassReference("somePackage.MyCustomControlsContainer");
}

I am planning on doing a post specifically about the new styling options but there are a couple of things to note here. styleNameFocus and styleNameNoFocus are just what they sound like. The styles they point to will be applied to the window depending on whether or not it has focus. (Which reminds me, there is now a hasFocus property on MDIWindow.) The other significant piece of the style declaration is the windowControlsClass style which, as you can see points to a ClassReference. This class will be detected and applied when the windowStyleName property is set, if necessary, allowing full control over window styling at runtime.

Default behaviors

The process for preventing/delaying default behaviors has also changed slightly. We have implemented the behavior described by Darron Schall here as it really is more proper than our initial implementation. The gist is that you now use event.preventDefault() instead of event.stopImmediatePropagation() and instead of storing the event for later execution you store a copy of it by using event.clone(). Darron's post is worth reading though so if you have time I would recommend getting the full scoop.

I think those are all of the major changes in 1.1 but I plan on taking a closer look at some of the topics in dedicated posts in the future. I've got a crazy couple of weeks ahead of me but I will do my best to get them up soon. If you have requests or suggestions for particular topics you'd like to see covered let me know in the comments. You can also find the full documentation here and as always, let us know what you think!

I guess donating code isn’t enough anymore

Posted in Flex, flexmdi, pointless blather by Ben on the February 4th, 2008

The following is an unedited email thread I have had with a reader over the past week or so. I helped him learn how to add a SWC to a Flex project but apparently that (and FlexMDI) wasn't good enough. The quotes next to the green bars are mine.

Update: I have decided to remove Keith's identifying information from this post. While I haven't received any kind of apology from him, as one commenter pointed out some employers could deem his behavior enough to warrant termination from a job or perhaps prevent the acquisition of a future job. Nothing of that magnitude was what I intended by publishing this. I was simply trying to point out two things. One, don't be ungrateful, especially when getting something at no cost. Two, just because you're communicating "on the internet" doesn't mean its OK to be a jerk, and your actions may very well become public knowledge. I think this post still accomplishes its goals without his info. So you're welcome Keith, again.

Hey Ben,

Thanks again for all the help in getting the demos to work. As I mentioned in my last post the only problem I am having now is trying to get the maximize and minimize events to work. When I add one of them to a I get "Event type 'mdi.events:MDIWindowEvent' is unavailable"

Any ideas??

Thanks,

Keith

Not sure what you mean exactly, can you show some code?

sure
... code snippet ...

When I compile that I get "Event type 'mdi.events:MDIWindowEvent' is
unavailable" on the MDIWindow code. If I remove
the "maximize" event parameter it compiles and runs fine.

Sorry, I dunno. Maybe try importing MDIWindowEvent?

Ben

Sadly it already is. I just took the sample code and added the maximize parameter.

So its just the explorer with one attribute added?

Any idea ?

Sorry, I don't really have time to investigate right now. I would suggest posting your issue on flexcoders.

Ben

Lol. Ok. I didn't realize they would comment on 3rd party code. I apologize -- I thought you were one of the developers of this component.

No problem, I am, I just have a lot going on right now. Sorry.

You knoiw what never mind. Pisses me off to no end when a developer won't take the time to troubleshoot his own code. I'd fire you if you worked for me. Guess now that its published and the articles have been written and your presentations made you don't give a flip.
There is a another component someone else wrote. I'll just check it out instead.
Maybe I will post to flexcoders and explain that the person who helped write it wouldn't take the time to help out. Yeah that should look good.
Thanks for ummm.. Well nothing I guess. Enjoy

Wow, you're amazing you know it? I have a family, a full-time job and other shit going on, I've spent countless hours writing the code, written articles, answered several questions on my blog (including yours) and on flexcoders, and because I don't have time to investigate your question right now that makes me a bad person/developer? You've been given a very good library for zero cost and you throw a temper tantrum because I can't personally investigate your issue? Why can't you post to flexcoders? Shit man, put forth some effort! The code has been downloaded over 6000 times and nobody has ever reported this issue. Doesn't mean its not a valid problem, but asking you to do a little bit more than flood my inbox whining that it doesn't work is a reasonable request. Please do post your complaint to flexcoders. Please.

Jeez man, you couldn't be more unappreciative. What exactly makes you feel entitled to free code plus support? Tell you what, send me $100 and I will be glad to investigate your issue personally. After all, I am sure you're getting paid for the project you're using our code in, so lets be fair and share the wealth. Right?

Unbelievable.

Ben

Come heckle me at 360|Flex Atlanta

Posted in 360|Flex, Flex, flexmdi, pointless blather by Ben on the January 29th, 2008

In just under a month, the amazing Tom and John will, once again, orchestrate what is sure to be an amazing conference. If you have any desire at all to improve your Flex skills, meet fellow developers, find a Flex job, hire a Flex developer or just have a really good time with lots of smart, cool people you should definitely attend. For $480 you can't beat it with a stick.

As the title implies, I will be speaking at the conference. My session is titled "Creating Flexible Components for Reuse and Distribution" and will discuss just that. I will be covering considerations and practices that are useful when you want to create something that will be useful beyond your immediate need or project. Most of the main ideas will be accompanied by examples from flexmdi since reuse and flexibility were main goals of the project, but the concepts will definitely be widely applicable. I would consider it an intermediate level session so you don't need to be a guru to attend, but hopefully the content will be interesting to developers of all skill levels, including you rock stars out there. Last time I checked I was speaking opposite Ben Forta so if you're a CFer I will understand if I don't see you. Otherwise come join me! The session will be pretty free-form and casual; if people want to shout out questions (or insults, whatever) in the middle thats fine by me. In fact, I hope there will be audience participation in the form of questions, comments, alternative approaches, etc. Should be a good time.

So I hope to see you in the audience, but even more so I hope to see you at the conference. Tom and John put on amazing events, have amazing passion for our industry and deserve nothing less than a stellar turnout. If you've never been to a 360 event, you owe it to yourself to experience it firsthand. Its awful friggin' cool. So come out, learn something, meet someone or just enjoy the ATL. I promise you won't regret it.

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!