Why does prefWidth in javafx takes an argument called height? - javafx

So I've been doing some work for my java class and noticed that Intellij IDEA gives me a warning I haven't seen before, when trying to set Pane's prefWidth. " 'WINDOW_WIDTH' should probably not be passed as parameter 'height' ". I didn't understanding this at first, but after some investigation I saw that Pane's prefWidth function takes an argument called height. And prefHeight takes an argument called width. Why is it like this? Did they accidentally mix up the names or is there something that I don't get?

Here's what the documentation of Node#prefWidth(double) says:
Returns the node's preferred width for use in layout calculations. If the node is resizable, its parent should treat this value as the node's ideal width within its range. If the node is not resizable, just returns its layoutBounds width, which should be treated as the rigid width of the node.
Layout code which calls this method should first check the content-bias of the node. If the node has a vertical content-bias, then callers should pass in a height value that the preferred width should be based on. If the node has either a horizontal or null content-bias, then the caller should pass in -1.
Node subclasses with a vertical content-bias should honor the height parameter whether -1 or a positive value. All other subclasses may ignore the height parameter (which will likely be -1).
Parameters:
height - the height that should be used if preferred width depends on it
Returns:
the preferred width that the node should be resized to during layout The result will never be NaN, nor will it ever be negative.
The documentation for the other width/height methods is similar. The above also mentions a content-bias which is handled by Node#getContentBias():
Returns the orientation of a node's resizing bias for layout purposes. If the node type has no bias, returns null. If the node is resizable and it's height depends on its width, returns HORIZONTAL, else if its width depends on its height, returns VERTICAL.
Resizable subclasses should override this method to return an appropriate value.
Returns:
orientation of width/height dependency or null if there is none
You'll also want to look at the documentation of Node#isResizable() (for brevity, I'm not going to quote it here).
So the reason Node#prefWidth(double) takes a parameter named "height" is because the computation of the preferred width may depend on the height. For instance, the FlowPane layout overrides getContentBias() and has it return the same value as its orientation property. When a FlowPane has an orientation of VERTICAL then the preferred width depends on the available height and if it has an orientation of HORIZONTAL then the preferred height depends on the available width.
Take note that there's a method for the minimum, preferred, and maximum width, same for the minimum, preferred, and maximum height:
Node#minWidth(double) - parameter name is "height"
Node#minHeight(double) - parameter name is "width"
Node#prefWidth(double) - parameter name is "height"
Node#prefHeight(double) - parameter name is "width"
Node#maxWidth(double) - parameter name is "height"
Node#maxHeight(double) - parameter name is "width"
Note: The above methods should probably not be called unless one is creating a layout. If you need the dimensions of a Node then look at its boundsInLocal or boundsInParent properties; if the Node is a Region it will also have read-only width and height properties.
Note: The above methods are different from properties of Region (e.g. Region#prefWidthProperty()).

Related

Fixing the size of layouts

Is there a way to make the layoutStretch property always be obeyed? E.g. I have it set to "1,3,2", but then a widget (a label) in the first part (the "1" in "1,3,2") expands (when more text is added), and then the 1:3:2 ration is no longer respected. That is, the "1:3:2" ratio turns into something more like "3:1:3".
You should take a look at the property QWidget::sizePolicy. It controls how the layout respects the sizeHint() of its children when it updates the geometries.
So what you need to do is: Make the layout ignore the horizontal sizeHints of the child widgets by setting the horizontal sizePolicy of the three child widgets to QSizePolicy::Ignored:
QLabel *label = ...;
...
label->setSizePolicy(QSizePolicy::Ignored, label->sizePolicy().verticalPolicy());
(The second argument will ensure that the vertical policy isn't changed by this statement.
Of course, you should set the size policy of every child widget, this example code is only for the label.)
Note that the contents of your layout have to be widgets; I think nested layouts can't be assigned a size policy (but I might be wrong). At least using QtDesigner, there is no way of applying a size policy to a layout itself (if it isn't the layout of a widget). See comments for details.
In QtDesigner, you can set the sizePolicy of the child widgets like this:
Before:
Shrinked:
Select the items in the layout:
Set the horizontal size policy to "Ignored":
Result:

Flex component setActualSize

I am a little confused about the setActualSize method. It appears from what I've read, that if it is not called on a component by its parent, the component will not be rendered.
So it appears that setActualSize is a critical method that is directly bound to rendering the UIComponent. It also appears that the width and height properties of UIComponent override the functionality of the width and height properties of flash.display.DisplayObject, in that they are not directly bound to the rendering of the object but are virtual values that are mainly used by the getExplicitOrMeasured when the parent of the component calls the component's setActualSize method.
So the question are:
1) Why isn't the default behavior of every component to just call setActualSize(getExplicitOrMeasuredWidth(),getExplicitOrMeasuredHeight()) on itself?
2) I guess this question stems from the above question and the behavior as I understand it as described above: does setActualSize change the visibility of the component?
It appears that that the behavior is that a component is not rendered until setActualSize is called, but if it contains display object children itself (expected behavior as it can calculate measure on itself) and is added to the display list, the only reason why flash isn't rendering it, is because its not visible.
The answers to your questions are in the way the Flex component life cycle works, consider these two phases:
measurement:
The Flex framework will call the measure() method of your component. You can override this method to set a default and/or minimum size for your component.
Flex components first measure themselves to provide a default and/or minimum size suggestion to the layout/container classes. Flex does this from a bottom up approach, so that the lowest level objects are measured first. Thus when each parent object measures itself, the preferred sizes of it's child objects has been established.
rendering:
Later Flex calls the updateDisplayList() method of your component. You can override this to size/position your component's child objects. This is where setActualSize() is intended to be used: the parent calls setActualSize() on it's child objects, not on itself.
Note the method signature of updateDisplayList():
protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
Measurement was done from the bottom up. However, rendering is done from the top down. So at render time, updateDisplayList(unscaledWidth, unscaledHeight) gets executed on your component. Flex is telling your component the space it has been allotted to render itself, and your component must size/position it's child objects accordingly and/or do programtic drawing.
The sizes passed in to updateDisplayList() are based on various factors:
how/if you override the measure() method (measure is not called when
your component has a fixed width/height)
the types of sizing
parameters (fixed, percent, constraint) and layouts that you use
An old but good resource on this topic
setActualSize() is one of the crutial and most interesting methods in Flex layout process:
1) Notice that setActualSize() is an entry point for parent's layout to set the component size, and it has to be called by parent (container) almost exclusively!
This is because only the parent knows the amount of space available for each child (this method is being called after all children are measured and the container knows it's own given size).
(note: the example of not calling it by layout posted below)
This method exists because if parent would set 'width' and 'height' on children directly, they would immediately turn into fixed size children, and they won't be measured anymore.
Using this method, only the rendering size is being changed - not the (explicit) width and height but _width and _height - meaning if for some reason the container resizes again, the children will be resized by given rules (percentage of the parent, expanding to child component's children size etc.)
2) Yes, because if this method isn't called at all, the component has a (rendering) size of (0, 0), so this is the reason of it's invisibility (not setting 'visible' to false)! ^_^
Note that THERE HAS TO BE A LAYOUT (even a non attractive one) to trigger this method call. By 'non attractive' I consider the layout that isn't supposed to do anything smart, like CHANGE THE WIDTH AND HEIGHT of children at all (like absolute layout)!
Now, look at the PopUpManagerImpl's class addPopUp() method: there is an interesting case of calling setActualSize():
IUIComponent(window).setActualSize(
IUIComponent(window).getExplicitOrMeasuredWidth(),
IUIComponent(window).getExplicitOrMeasuredHeight());
Explanation: PopUpManager does stuff that layout should normally do, because it WANTS TO KNOW THE POPUP DIMENSIONS IMMEDIATELY, so it could center the popup on stage. It has no time to wait for the layout pass!
If you comment those 3 lines in the framework code, you'll see that popup is being centered with it's top left corner - just like it's size is (0, 0). Anyway, it is rendered with proper width and height because at rendering time the dimensions are known.
Hope this makes things a bit clearer...
Cheers! ^_^
Danko Kozar

Unset the explicit height value of a flex component?

When a container component is declared without setting an specific height value, the contaniner's height will be automatically set to a value which makes possible to display all of its content/children without scrolling (when possible).
After the component is initialized with the proper height, I explicitly change the height value of the container.
My question is, after I change the component's height, is it possible to switch back to the original height that was automatically set based on the containers contents? I'm looking for some way to unset the explicit value of the component's height.
One trick that may be useful for you is to set the height to "NaN", which effectively "unsets" the explicit value you set earlier.
Without storing the original height before it was manually changed, I don't believe this is possible.
What you could do is extend whichever base object you're using as a container to add a new property called OriginalHeight (might as well add OriginalWidth while you're there).
Then you would override the set height function to store the original height in your new OriginalHeight property before it gets changed. When you need to set it back, you would just set the container's height = OriginalHeight.
contaniner's height will be
automatically set to a value
This is not quite automatic. A component will always set the height and width of children; but it can never set the height and width of itself. It can only make suggestions (using the measure method by setting the measuredHeight and measuredWidth property). It is up to the parent container whether it wants to use or ignore those measuredHeight / measuredWidth values.
The Flex Framework containers all have code written for calculating height / width / positioning. IF you are using those, it may seem automatic; but it is actually a fairly manual process. You're just using code someone else wrote.
If you explicitly change the height value of the container, how do you do it? Inside the container (this.height = newvalue ) ? Or does the parent somehow change the height (myContainer.height=newValue)?
Beyond that, it depends what the original height value was. It is possible you can use the measuredHeight value, but I wouldn't count on it. Although, if you are specifying absolute height and absolute width then measure will never be run.
Probably Jason's answer about storing the old value is the best one.

Flex 4: How to get actual width of a group when using 100% and top/bottom/left/right?

I have an application with width/height of 100%. I have several nested groups within and their measurements are all not set, instead being defined as top=5 or left/right=10, etc.
I'm trying to get the actual with of a group that should be 390. I've set the swf object size to be 400 from the html embed code, and the group is inside another group that is width=100%. The group has a left=5 and right=5 so the width should be 400-10. When I display the .width and .measuredWidth of this group, the width is always 400.
I'm fairly new to flex/flash. Do I need to have explicitly set widths in order to get the width of child containers? Is there something I'm doing wrong here?
Thanks!
Percentage size of Component is calculated at parent's updateDisplayList(),so it's available only through width & height.
Methods getExplicitOrMeasuredWidth/Height() may return following:
Explicit width/height
Or
Measured width/height when mode is set to Wrap. This is calculated during Component's measure().
If you do not plan to override measure or updateDisplayList you simply should not use getExplicit... at all.
Use the getExplicitOrMeasuredWidth() method of the UIComponent. This returns the explicit width if set (e.g., width="700") or the measured width (in pixels) if not. If a percentage width is set, it returns the actual measured width.
It turns out there was an inner group with a path that was throwing the layout off. When I removed this element, the .width property worked as it had before.
One thing that surprised me is that .measuredWidth and getExplicitOrMeasuredWidth() both returned 10 when .width returned 390.
I believe that it's returning the right value. If you have an application A, width 400. Then you put group B inside it with width 100% and some padding. Group B really is 400, because it's extended all the way to the edges of the application. However, by giving it left/right/padding/whatever, it, in turn, can adjust its children so they aren't so close to the edges. You may need to look for the maximum width of group B's children to get what you want.
Update:
According to documentation:
http://livedocs.adobe.com/flex/3/html/help.html?content=size_position_5.html
Using constraint-based layouts overrides width and percentWidth. Try measuredWidth, though it may not be filled until the component has had time to go through its measure() phase during invalidation...

In Flex, how can I get the dimensions of a childless canvas component at runtime?

One of my components looks like this:
<mx:Canvas id="grid" width="100%" height="100%"></mx:Canvas>
On creationComplete, I load some spirte that I want to scale and position based on the dimensions of the canvas to create a custom grid layout, but when I access the dimensions of 'grid' I get 0 and 0. Is there any way to get the dimensions without assigning absolute values?
I can't check this at the moment but can you access the measuredHeight and measuredWidth?
My understanding is that unless the Canvas contains one or more DisplayObject children, it will always report its width and height properties as 0, regardless of the percentage sizings you may have applied to it.
You could always add an empty dummy DisplayObject to the Canvas, but that wouldn't be very elegant. Depending on how you've planned to implement your custom grid, it's possible you'll have to rethink the design...
Is it possibly created but not yet displayed (e.g. visible)? Since final size and shape is derived, it doesn't happen until the thing actually needs to be drawn. Width and height are documented to be the values actually in use - there are even events for when they change.
Worst case, try trapping it out in the canvas Resize event.
have you tried binding the width and height of the Canvas to its parent? If it is 100%, than it will have the same size as its parent and you could either bind or size your Sprite (UIComponent) based on the parent container of the Canvas.

Resources