Controls: autoSize

One bug which gets filed over and over again is related to the idea of whether Controls should resize themselves when their content / settings change. The earliest such bug was with TextBox. TextBox has a columns property which, like in Swing, can be used to hint how many “columns” of text should be displayable in the Control by default. The TextBox skin implementation uses this information in conjunction with the font and other settings to determine the preferred width of the TextBox.

When a Control is created, if you do not explicitly specify its width or height, then it is sized according to its preferred width and/or preferred height. If you use a Control within a layout Container (which was anticipated as being the common case) then you (almost) never explicitly manage its dimensions – you leave that chore to the Container. However, if you do not use a Control within a layout Container (which turns out seems to happen quite a bit) then it does not explicitly resize itself whenever, say, columns changes.

Take Button as another example. If you create a Button with the text “OK” and do not specify a width or height, then the Button will be initialized to its preferred size. However, if you then change the text of the Button to be “Cancel”, then the Button will not automatically resize, and will therefore not be wide enough to display all the text and you’ll see something like “C…”, if you’re lucky. Or “…” if you’re not.

I’ve filed RFE http://javafx-jira.kenai.com/browse/RT-5122 targeted at the next release. The idea here is to have an “autoSize” variable on Control which will be true by default. Problem solved, right? Well, not quite. The problem with autoSize is that when placed in a Container, the Control should not attempt to resize itself. So we’ll end up with code essentially like this:

if (autoSize and not (parent instanceof Container)) {
// resize the width because the text has changed, or whatnot
}

Not very pretty. But given the options and the amount of frustration it is causing developers, I’m willing to accept that bit of nastiness. What do you think? Have any good ideas? Leave comments & votes on the bug if you like!

5 Comments

autoSize is a good idea, that’s the way the problem is handled in other RIA platforms as well. It might be good to generate a compiler warning if someone places a button in a container and sets autoSize: true.

With the possible exception of a hyperlink, very very rarely do I ever really want a control to resize itself once displayed. If I had a button with a label which changed from “Ok” to “Cancel”, I’d prefer it to be pre-sized to accept the larger text right from the start, precisely because visible resizing generally looks ugly (and unprofessional).

Perhaps a better strategy might be to not have the controls dynamically resize simply because their contents have changed (obviously fonts changes, etc, are a different matter entirely), but to provide easier ways to hint at their maximum potential size, without having to monkey about with pixel dimensions…

@Raju: the compiler warning isn’t a good idea if autoSize can be changed dynamically. Or perhaps it should be public-read init.

I fully agree with Simon, unless you need special effects, most controls should have a fixed size, and in case of special effects, if the control extends Resizable (they all do, no?), you can just change width or height properties.

When you change the content of a control, you can also trigger a resize request, eg. fitTocontent() or similar. Or provide functions to get the size of the modified content, depending on font and stuff, so that the program can resize manually the control (might want to stick to a number of predefined sizes, add margins, etc.).

How about rather than introducing a new variable you make use of the existing LayoutInfoBase.managed variable. According to the API docs, this variable “Defines whether the node(s) referencing this layout info should have their layout managed by their parent container.”

This could also be interpreted as having the size self-managed by the control if it is set to false.

Some other reasons why this conveniently works out include:
* It defaults to true (which is exactly what you wanted for your autoSize proposal)
* It resizes the component properly in the non-managed Container case
* It works with other UI elements that are not Controls (e.g. Charts)

When the app sets the width/height of a control and places it in a container, which promptly resizes it to its preferred size. Turns out this is by-design and the supported way of handling this is to override the control’s preferred size like this:

layoutInfo: LayoutInfo { width: myWidth height: myHeight }

However, this is not necessarily intuitive and I have a number of JIRA issues filed because developers were surprised that their width/height settings were lost when the control was placed in a container (e.g. hbox/vbox). I haven’t closed the issues as “will not fix” until time convinces me developers just need to learn this idiom.