Stopping GroupLayout components from stretching vertically - swing

Is there an easy way to get all (or most) of the components in a GroupLayout application NOT stretch vertically? I know I can do it by forcing each component to it's preferred size when I add it, but that makes the code so much more verbose:
.addGroup(layout.createSequentialGroup()
.addComponent(oDevRadio)
.addComponent(oInstRadio)
)
Becomes
.addGroup(layout.createSequentialGroup()
.addComponent(oDevRadio,
GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE)
.addComponent(oInstRadio,
GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE)
)
Is there a way to set it as a default, and just specify the elements I want to be stretchable?
References
- addComponent's spec

As far as I know, the only method of telling GroupLayout components not to stretch or otherwise be misaligned requires that the relevant components be inside a ParallelGroup. It is then a simple matter to set the resizeable flag of the ParallelGroup to false.
Javadoc of ParallelGroup creator with relevant flag
For example, in the following code jspCasts is a very tall component. Without a new ParallelGroup with the flag being set to false, components next to it would either stretch or not align neatly as they should.
vGroup.addGroup(gl.createParallelGroup(Alignment.LEADING).
addComponent(jspCasts).
addGroup(gl.createParallelGroup(Alignment.CENTER, false).
// without worrying about vertical stretching or misalignment,
// add your components here

Not as far as I know. I've handled it with a utility class:
package alpha;
import java.awt.Component;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Group;
public class GroupLayoutUtil
{
public static GroupLayout.Group addPreferred(Group g, Component c)
{
return g.addComponent(c, GroupLayout.PREFERRED_SIZE,
GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE);
}
}

Related

Is JPanel supposed to be added to a JFrame?

I have this code which I don't understand:
JFrame jframe = new JFrame("Risultati protocolli cercati");
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel body = new JPanel();
Container c = jframe.getContentPane();
body.setSize(100, 100);
body.setLayout(new GridLayout(1000, 1));
for (int i = 0; i < 1000; i++)
body.add(new JLabel("JLabel " + i));
JScrollPane jsp = new JScrollPane(body);
c.add(jsp);
jframe.setSize(100, 100);
//jframe.add(body);
jframe.setVisible(true);
If I leave the penultimate line commented then everything appears, both labels and scroll. Instead if I uncomment that line, I see nothing. Only the JFrame. Why does it happens? For the main window of my program I had to perform jframe.add(body)...
Instead if I uncomment that line, I see nothing. Why does it happens?
The below line
jframe.add(body);
internally calls
jframe.getContentPane().add(body);
JFrame by default uses BorderLayout and add(component) method directly add it in the center section, if you add again then last one is replaced with latest one.
You can use overloaded add() method of JFrame to add it in another section east, west, north and south as shown in below snapshot:
for e.g.:
frame.add(comp,BorderLayout.NORTH); // add in north section
frame.add(comp,BorderLayout.WEST); // add in west section
You can use other Layout Managers as well as per the design or your application:
It's worth reading How to Use BorderLayout
One more suggestion:
Use frame.pack() instead of frame.setSize() that fits the components as per component's preferred size.
Interesting problem caused by the layout managers.
A component can only have a single parent. First you add the "body" to the scrollpane but then the "body" gets removed from the scrollpane when you add it to the content pane of the frame (for the reasons mentioned by #braj). Not a big deal as it just means you won't see any scrollbars.
Since the component is directly added to the content pane you should still see the labels however they do not display and this is the confusing part. Change your code to use "100" for the GridLayout and the number of components you create in the loop. When the frame first displays the panel will be empty. Now, increase the height of the frame and you will see the components appear. What is happening is that you are trying to paint too many components in a small area and because of rounding issues the height of every component becomes 0, so there is nothing to paint. When you increase the height to at least 100 pixels every component can now be 1 pixel high so you get garbage.
The only solution is to keep the "body" panel in the scrollpane so that all components will be displayed at their preferred size. Then you can scroll through all the components as required.
A tip for when using a GridLayou. You can use:
body.setLayout(new GridLayout(0, 1));
Then means the grid will have unlimited rows and a single column.

AS3: Who should I layout first the parent or the children?

I am building large application in Starling and one of my main problems is who should I layout first: the parent or the children?
What is the default behavior in starling and also in flash:
By default Sprite will get his size based on his children after they have been added to stage.
What if I want to layout the children based on the parent? For example: What if I want to set one of the children to be at position of 20 pixels from the bottom, like bottom menu?
In this case I should:
Add the children
Determine their sizes. If you are building your application cross platform, you need to support many screens, and many times you come to have complicate logic for calculating the scale percentage of your components, which is their size.
Determine your size and layout yourself.
now the bottom menu could be layout at 20 pixels from the bottom. Also it doesn't matter if you place this logic inside the bottom menu or it's parent.
But this not always the case, sometimes you want to layout the parent based on his children. A common example if one of the children is the parent background. In this case you should:
Add the background.
Determinate background size and layout it.
Now you can layout the parent.
But what if I got both of the cases? If one of parent children is background and the other is bottom menu? What if the bottom menu got his own background and other children that need to be layouted base on the parent?
What solution can be used so I will not get lost inside all of this, and can Gazman SDK help here?
What you need is to create layout dependencies between all the components. Each Sprite should have an event that tells us when its layouting is complete.
Now if you have some layouting logic inside the parent that cannot start until its background child is complete layouting, you should create a dependency between the background and the parent. The parent should listen to LayoutComplete event from the background and then he can layout himself, and when he complete layouting he can dispatch LayoutComplete event, and now its child bottom menu can layout himself.
You can implement it yourself or use Gazman-SDK that do exactly that. If you choose Gazman-SDK your code will look like this:
public class ParentClass extends Group
{
private var background:Background = new Background();
private var bottomMenu:BottomMenu = new BottomMenu();
override protected function initialize():void
{
// check if not already added to stage
if(!background.parent){
addChild(background);
addChild(bottomMenu);
}
// Create dependency for background. If background have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// background initialize is complete
if (subscribeForInitilize(background)){
return;
}
// do layouting logic here
}
}
public class BottomMenu extends Group
{
override protected function initialize():void
{
// Create dependency for parent. If parent have not
// been initialized yet the subscription will succeed
// And this.initialize() will be called again once
// parent initialize is complete
if (subscribeForInitilize(parent as Group)){
return;
}
// do layouting logic here
}
}

addChild(Button) in AS3

I am writing a class that extends mx.core.UIComponent. In the constructor of this class, I would like to add a Button (spark.components.Button). However, creating a new Button object (such as var b:Button = new Button();) and then doing this.addChild(b) doesn't work -- no button is appearing. Is there any reason why a Button object can't be added as a child?
Edit: Just to add, when I print out the children, it says that the Button object is a child, but the Button doesn't show up.
You need to add the button in the createChildren method not in the constructor.
protected var button:Button;
override protected function createChildren():void {
super.createChildren();
button = new Button();
addChild(button);
}
Depending on what you are trying to do you may also need to implement the measure and updateDisplayList methods.
Using UIComponent directly, you aren't getting the layout of the child handled for you; you would need to set the position and size of your child components manually (see docs).
Consider using a Group (or Canvas, if you're still on MX components) to handle child layout. You can still add rendering in updateDisplayList, just make sure you call super.updateDisplayList() as well.
You need to read up on the differences between ActionScript components and Flex components. When using a Flex component, you must use container.addElement( element ), not container.addChild( child ). As far as I am aware, the only classes with this functionality descend from Group (at least in the Spark framework, the one I am most familiar with). So extending UIComponent will not allow you to add a Button, although a UIComponent can be added to a Flex container (which I do not believe a normal Sprite can do)

Movieclip stacking in Actionscript

I'm building a game of which the interface is one of the first items to load on screen. Sound button, pause and all the bits -
During the game - all manor of things are dynamically added and removed to the stage. Therefore my interface goes behind my game scene.
How do I ensure the movieclip always stays on top?
Can I override the addChild of my Document Class and every time a new child is added, I restack the interface to the top?
You can use setChildIndex to rearrange objects that are already contained within a MovieClip or Sprite. For example, if you have an object called container, which contains a redBall, blueBall and many other ball objects, you can use the following to make sure redBall is behind everything else:
container.setChildIndex(redBall, 0);
Equally you can make sure that blueBall will be displayed infront of everything else using:
container.setChildIndex(blueBall, container.numChildren-1);
addChildAt will sort you out for adding children straight into their correct position, and setChildIndex will allow you to re-position objects already placed. Hope that helps.
debu
Look into addChildAt, it allows you to specify the index that the new object should be added too.
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/DisplayObjectContainer.html#addChildAt%28%29
A good strategy is to keep all interface elements in one parent Sprite/MovieClip, and all game assets in another. (With the interface one on top)
With your guys suggestion I made this, apparently, if you addChild an object already on the screen, it's simply reindex'd to the top. Does this look ok?
private var topLevelChildrenArray:Array = [];
public function addTopLevelChild(child:DisplayObject):DisplayObject
{
topLevelChildrenArray.push(child)
return this.addChildAt( child, this.numChildren - 1 );
}
override public function addChild(child:DisplayObject):DisplayObject
{
this.addChildAt(child, this.numChildren);
for each(var topChild:DisplayObject in topLevelChildrenArray)
{
super.addChild(topChild);
}
return child
}

Qt Widget Overlays

How do I overlay widgets in Qt?
I want to create some widgets and place them out-of-layout, but rather tweak their size and position when some other widget's geometry is changed.
Something like the buttons on the screenshot:
You just need to create your QPushButton (or any QWidget), indicate its parent QWidget and then display it.
Don't add it to the parent layout else you will not be able to move it as you want.
Don't forget to indicate its parent else it will be displayed as independant QWidget.
In these conditions your QPushButton will be considered as child of the QWidget but not member of the parent's layout. So it will be a "floating" child and you must manage it's behaviour when resizing parent's QWidget.
If you want a unified behaviour for all overlay buttons, you should subclass QLayout and redefine members bahaviour.
If they're child of a widget without a layout, you should be able to move them around as you please, I think.
I needed a widget like this for a project I'm working on, so I took Patrice advice and wrote this code (Python) PyQt4 Widget Overlay