Wednesday, April 1, 2009

Titled Border Box and Titled Border Panel

** There is a Flex 4/Spark version of this control which can be found here.

I've written two new components called TitledBorderBox and TitledBorderWindow that both render a solid border around the component with a title textfield at the top. They are similar to TitledBorder in Java, and the <Fieldset> tag in HTML.

Skip straight to the examples - here are three TitledBorderBox components that illustrate the three layouts (vertical, horizontal, and absolute) and various title styles (right-click to View Source):


And here is an example of the TitledBorderWindow that illustrate how the border and background changes with the various properties (right-click to View Source):


Here are the properties and styles:
<ui:TitledBorderBox
  Properties
layout="vertical|horizontal|absolute"
title=""
borderDropShadow="false"
Styles
backgroundAlpha="0"
backgroundColor="0xffffff"
borderAlpha="1"
borderColor="#000000"
borderThickness="1"
cornerRadius="0"
horizontalGap="8"
paddingLeft="5"
paddingTop="5"
paddingRight="5"
paddingTop="5"
verticalGap="6"
titleStyleName="windowStyles"/>

<ui:TitledBorderWindow
  Properties
layout="vertical|horizontal|absolute"
title=""
borderDropShadow="false"
Styles
backgroundAlpha="0"
backgroundColor="0xffffff"
borderColor="#000000"
borderThickness="1"
borderAlpha="1"
cornerRadius="0"/>
Set the cornerRadius style to have rounded corners. The TitledBorderWindow also supports the roundedBottomCorners boolean style too if you only want rounded corners at the top. And both components can have an optional drop shadow filter as well.

The TitledBorderWindow extends TitleWindow (which extends Panel) so it has all the same properties and styles. The styles that have changed from the Panel/TitleWindow defaults are listed above. I've also added support for adding custom buttons to the titleBar (next to the closeButton).

Update (April 14th 2009): The TitledBorderWindow class wasn't properly laying out the ControlBar like the Panel class does, so I've added a fix for it.

Update (March 17th 2010): scrollbars weren't correctly on the TitleBorderBox class when you use either the horizontal or vertical layout (and you restrict the size of the box). I've fixed up the borderMetrics function to property return the size of the border and now the scrollbars work properly. I also noticed that the background color didn't work if you set the layout to absolute, and that is fixed too.

Update (June 1st, 2010): I've made a Flex 4/Spark version which can be found here.



25 comments:

  1. hi. nice components. its free? where i cand download it?

    ReplyDelete
  2. Haha, yes it's free. Maybe I should charge for it?

    To download the source code right click on either of the two Flex examples above and choose "View Source". This will open a new window that shows the source code. You can either copy and paste the classes that you want, or there is a link in the bottom left corner that lets you download the zip file.

    ReplyDelete
  3. Thank you, Chris.
    Good job!
    It is a good example how to write custom AS components.

    ReplyDelete
  4. It is very nice and easy, thank you.
    You can share this one and other nice components with others by the flexlib project (code.google.com/p/flexlib)

    Thanks!

    ReplyDelete
  5. Thanks for this. I'm using Flex Builder 3 and although this component shows up in the Components window (under Custom) it does not show up when I drag it onto another component. I'm probably overlooking something obvious, but I can't see it.

    ReplyDelete
  6. Hi,
    This is something that unfortunately happens in Flex Builder 3 when you are using a custom component that is in the same project as your application. If your custom component is in a separate project, then it would show up properly in the Design Mode view.
    I've actually written a blog post on this issue, which includes one possible workaround for this problem:
    http://flexdevtips.blogspot.com/2010/03/custom-components-live-preview-design.html

    Chris

    ReplyDelete
  7. Chris, I'm trying to use this component in my project. It still doesn't seem to handle scrollbars on the box. It displays a small amount of the content outside of the border when scrolling.

    ReplyDelete
  8. Which component are you using - the box or the window?

    ReplyDelete
  9. Hi Chris,

    Thanks for the great component. I have one question regarding the TitledBorderBox. I am using the component in a TitleWindow that is being displayed through the PopupManger control. The title for the TitledBorderBox is not being displayed. I've set break points in the TitledBorderBox class and everything seems to be in order. Any suggestions.

    ReplyDelete
  10. Hi Brian,

    I'm not sure why it doesn't work for you. I created a very simple sample in ActionScript to try and duplicate your problem, and it works as expected (both titles appear)

    var popup:TitleWindow = new TitleWindow();
    popup.title = "TitleWindow";
    popup.width = popup.height = 300;
    popup.showCloseButton = true;
    popup.addEventListener(CloseEvent.CLOSE,
    function(event:CloseEvent):void {
    PopUpManager.removePopUp(popup);
    });

    var tbb:TitledBorderBox = new TitledBorderBox();
    tbb.title = "TitledBorderBox";
    tbb.percentHeight = tbb.percentWidth = 100;
    popup.addChild(tbb);

    PopUpManager.addPopUp(popup, this);
    PopUpManager.centerPopUp(popup);

    If you are still having problems, then post a snippet of your source code and I'll try to help you debug it.
    Chris

    ReplyDelete
  11. I suggest a modification in the provided code.
    Line 303 to Line 326


    override protected function measure():void {
    super.measure();
    layoutObject.measure();

    var measuredSize:Rectangle = measureTitleText();
    var paddingW:int = 38;
    measuredMinWidth = Math.ceil(Math.max(measuredSize.width + paddingW, measuredMinWidth));
    measuredWidth = Math.ceil(Math.max(measuredSize.width + paddingW, measuredWidth));
    measuredMinHeight = Math.ceil(Math.max(measuredSize.height, measuredMinHeight));
    measuredHeight = Math.ceil(Math.max(measuredSize.height, measuredHeight));
    }

    private function measureTitleText():Rectangle {
    var textWidth:Number = 20;
    var textHeight:Number = 14;
    if (titleTextField && titleTextField.text) {
    titleTextField.validateNow();
    var textFormat:UITextFormat = titleTextField.getUITextFormat();
    var metrics:TextLineMetrics = textFormat.measureText(titleTextField.text, false);
    textWidth = metrics.width;
    textHeight = metrics.height;
    }
    return new Rectangle(0, 0, Math.ceil(textWidth), Math.ceil(textHeight));
    }

    It can avoid a bad measure in some case of decimal value

    ReplyDelete
  12. Thanks for that suggestion, it looks like a good idea to me.
    Chris

    ReplyDelete
  13. Perfect. You have a gift my friend. Don't hide that in a bushel.

    ReplyDelete
  14. Hi,

    Great component. Can you submit it to the OSS flexlib library or add a license so you can legally use it in a professional environment ?

    Here is the opensource license list:
    http://www.opensource.org/licenses/alphabetical

    Thanks !

    ReplyDelete
  15. Sure, I've made it part of LGPL 3.0 which is in the list.

    Cheers.
    Chris

    ReplyDelete
  16. Thanks, it really help me

    ReplyDelete
  17. Really nice component you made here, many thanks. I'm currently using it and would like to make a comment about using an embed font for the box title.

    Strangely enough, if your embed font is compiled with embedAsCFF=true, the border will come over the title.

    I debuged a little bit and discovered that the UIComponent.measureText method call (inside TitledBorderBox.updateDisplayList) returns a text width of 0. If executed in debug mode, the compiler will Trace a warning complaining that the font is not compatible and must be compiled with embedAsCFF=false.

    I checked and it worked great. I did not look deeper for the cause of this behavior, but I hope this comment will help.

    Cheers

    ReplyDelete
  18. Mea culpa, setting embedAdCFF=false did not work since the component is a Spark Label and not a Mx Label. A workaround that seems to work: using titleLabel.measuredWidth instead of var metrics:TextLineMetrics = titleLabel.measureText(titleLabel.text);

    ReplyDelete
  19. Good to know, thanks for the comment!
    Chris

    ReplyDelete
  20. Hi Chris,
    I have used this component in Flex 3 and it works fine, thanks for that!
    But now, when I compile this using Flex 4.6, the controls inside the component are not showing up ...
    Can you please help ??

    Thanks for the help in advance.

    - Ramesh

    ReplyDelete
  21. Hi Ramesh,

    Have you tried using the Flex 4/Spark version of this control? I wrote a separate blog entry on it, which can be found here.

    Chris

    ReplyDelete
  22. Thanks Chris,
    Yes, I saw the Flex 4 version.
    But, unfortunately, my requirement is to get the same Flex 3 version working as I cannot migrate to Spark components as of now.

    Is there a way to get this version working on Flex 4?

    - Ramesh

    ReplyDelete
  23. Hi Ramesh,

    I apologize, but I no longer work in Flex 3 so I can't help you. I don't think I even have Flex Builder 3 installed anywhere.

    Good luck,
    Chris

    ReplyDelete