# FlowLayout Buttons verschieben?



## b1zarRe (5. Okt 2011)

Hi,

ich wollte nur kurz erfragen, ob es möglich ist, mithilfe einer Methode, im FlowLayout
Button oÄ zu verschieben? Ich habe 2 Buttons nebeneinander, möchte aber das diese zb
untereinander sind, ohne die Größe des Fensters zu verschieben.

Mir ist klar, dass es auch andere Layouts gibt, wo man alles von hand positionieren kann, wie man
will... jedoch habe ich schon angefangen im FlowLayout alles halbwegs passend zu programmieren und würde ungern alles umschreiben für diesen einen Button.

Pls help,
thanks


----------



## André Uhres (5. Okt 2011)

Hallo B1zarRe,

wenn der horizontale Platz im Container zu klein ist, um alle Komponenten in eine Zeile zu setzen, verwendet das FlowLayout mehrere Zeilen. Wir können also z.B. die Buttons in ein JPanel setzen, das eine entsprechende PreferredSize hat, so dass das FlowLayout die Buttons untereinander platziert.

Gruß,
André


----------



## b1zarRe (5. Okt 2011)

Ok vielen dank fuer die rasche antwort! Werde ich morgen probieren mit den panels, sollte ja egtl. Nich so schwierig werden; aber bisher mit diesen nicht gearbeitet. Haettest du vllt. Ein stueck code (falls es nicht zu aufwaendig ist & du zeit hast)?


----------



## hdi (5. Okt 2011)

> Mir ist klar, dass es auch andere Layouts gibt, wo man alles von hand positionieren kann, wie man
> will... jedoch habe ich schon angefangen im FlowLayout alles halbwegs passend zu programmieren und würde ungern alles umschreiben für diesen einen Button.



Das Ding ist: Es macht keinen Unterschied ob du nun für ein neues Panel ein FlowLayout mit entsprechend kleiner preferredSize addest (wie André es vorschlägt) oder halt ein Panel welches gleich ein BoxLayout mit vertikaler Anordnung verwendet. Es ist einfach etwas doof zu sagen "Ich will nur FlowLayouts, auch wenn es gar nicht passt und alles verkompliziert". Es gibt nicht nur die beiden Wege a) FlowLayout oder b) alles per Hand. Es gibt genügend andere Layouts die genauso einfach sind wie das FlowLayout. Wie gesagt, für die Anordnung untereinander nimm ein BoxLayout (PAGE_AXIS)

edit: Ich glaube ich hab dich jetzt erst beim zweiten Lesen deines Beitrags richtig verstanden. Die Antwort lautet:
*Nein*, du kannst nicht innerhalb eines FlowLayouts mit mehreren Komponenten _ein Teil_ dieser Komponenten untereinandern anordnen, ohne das mit anderen Containern zu schachteln!


----------



## jgh (5. Okt 2011)

du kannst dir natürlich einen Layout-Manager nehmen, der das von dir gewünschte Verhalten implementiert. (Flow-Layout nur Vertical positioniert)
Bspw. hier gibt es sowas.


```
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.util.Hashtable;

import javax.swing.JButton;
import javax.swing.JFrame;

public class VerticalFlowLayoutTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		JFrame f = new JFrame();
		f.setExtendedState(JFrame.MAXIMIZED_BOTH);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setLayout(new VerticalLayout());
		for (int i = 0; i < 10; i++) {
			JButton b = new JButton("xxxxxxxxxxx");
			f.add(b);
		}
		f.setVisible(true);
	}

}

/**
 * THIS PROGRAM IS PROVIDED "AS IS" WITHOUT ANY WARRANTIES (OR CONDITIONS),
 * EXPRESS OR IMPLIED WITH RESPECT TO THE PROGRAM, INCLUDING THE IMPLIED
 * WARRANTIES (OR CONDITIONS) OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE. THE ENTIRE RISK ARISING OUT OF USE OR PERFORMANCE OF THE PROGRAM AND
 * DOCUMENTATION REMAINS WITH THE USER.
 */

/**
 * 
 * A vertical layout manager similar to java.awt.FlowLayout. Like FlowLayout
 * components do not expand to fill available space except when the horizontal
 * alignment is <code>BOTH</code> in which case components are stretched
 * horizontally. Unlike FlowLayout, components will not wrap to form another
 * column if there isn't enough space vertically. VerticalLayout can optionally
 * anchor components to the top or bottom of the display area or center them
 * between the top and bottom.
 * 
 * Revision date 12th July 2001
 * 
 * @author Colin Mummery e-mail: [email]colin_mummery@yahoo.com[/email]
 *         Homepage:[url=http://www.kagi.com/equitysoft]CellSpark - Java software and consulting[/url] - Based on 'FlexLayout' in Java
 *         class libraries Vol 2 Chan/Lee Addison-Wesley 1998
 */
class VerticalLayout implements LayoutManager {

	/**
	 * The horizontal alignment constant that designates centering. Also used to
	 * designate center anchoring.
	 */
	public final static int CENTER = 0;
	/**
	 * The horizontal alignment constant that designates right justification.
	 */
	public final static int RIGHT = 1;
	/**
	 * The horizontal alignment constant that designates left justification.
	 */
	public final static int LEFT = 2;
	/**
	 * The horizontal alignment constant that designates stretching the
	 * component horizontally.
	 */
	public final static int BOTH = 3;

	/**
	 * The anchoring constant that designates anchoring to the top of the
	 * display area
	 */
	public final static int TOP = 1;
	/**
	 * The anchoring constant that designates anchoring to the bottom of the
	 * display area
	 */
	public final static int BOTTOM = 2;
	private int vgap; // the vertical vgap between components...defaults to 5
	private int alignment; // LEFT, RIGHT, CENTER or BOTH...how the components
							// are justified
	private int anchor; // TOP, BOTTOM or CENTER ...where are the components
						// positioned in an overlarge space
	private Hashtable comps;

	// Constructors
	/**
	 * Constructs an instance of VerticalLayout with a vertical vgap of 5
	 * pixels, horizontal centering and anchored to the top of the display area.
	 */
	public VerticalLayout() {
		this(5, CENTER, TOP);
	}

	/**
	 * Constructs a VerticalLayout instance with horizontal centering, anchored
	 * to the top with the specified vgap
	 * 
	 * @param vgap
	 *            An int value indicating the vertical seperation of the
	 *            components
	 */
	public VerticalLayout(int vgap) {
		this(vgap, CENTER, TOP);
	}

	/**
	 * Constructs a VerticalLayout instance anchored to the top with the
	 * specified vgap and horizontal alignment
	 * 
	 * @param vgap
	 *            An int value indicating the vertical seperation of the
	 *            components
	 * @param alignment
	 *            An int value which is one of
	 *            <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal
	 *            alignment.
	 */
	public VerticalLayout(int vgap, int alignment) {
		this(vgap, alignment, TOP);
	}

	/**
	 * Constructs a VerticalLayout instance with the specified vgap, horizontal
	 * alignment and anchoring
	 * 
	 * @param vgap
	 *            An int value indicating the vertical seperation of the
	 *            components
	 * @param alignment
	 *            An int value which is one of
	 *            <code>RIGHT, LEFT, CENTER, BOTH</code> for the horizontal
	 *            alignment.
	 * @param anchor
	 *            An int value which is one of <code>TOP, BOTTOM, CENTER</code>
	 *            indicating where the components are to appear if the display
	 *            area exceeds the minimum necessary.
	 */
	public VerticalLayout(int vgap, int alignment, int anchor) {
		this.vgap = vgap;
		this.alignment = alignment;
		this.anchor = anchor;
	}

	// ----------------------------------------------------------------------------
	private Dimension layoutSize(Container parent, boolean minimum) {
		Dimension dim = new Dimension(0, 0);
		Dimension d;
		synchronized (parent.getTreeLock()) {
			int n = parent.getComponentCount();
			for (int i = 0; i < n; i++) {
				Component c = parent.getComponent(i);
				if (c.isVisible()) {
					d = minimum ? c.getMinimumSize() : c.getPreferredSize();
					dim.width = Math.max(dim.width, d.width);
					dim.height += d.height;
					if (i > 0)
						dim.height += vgap;
				}
			}
		}
		Insets insets = parent.getInsets();
		dim.width += insets.left + insets.right;
		dim.height += insets.top + insets.bottom + vgap + vgap;
		return dim;
	}

	// -----------------------------------------------------------------------------
	/**
	 * Lays out the container.
	 */
	public void layoutContainer(Container parent) {
		Insets insets = parent.getInsets();
		synchronized (parent.getTreeLock()) {
			int n = parent.getComponentCount();
			Dimension pd = parent.getSize();
			int y = 0;
			// work out the total size
			for (int i = 0; i < n; i++) {
				Component c = parent.getComponent(i);
				Dimension d = c.getPreferredSize();
				y += d.height + vgap;
			}
			y -= vgap; // otherwise there's a vgap too many
			// Work out the anchor paint
			if (anchor == TOP)
				y = insets.top;
			else if (anchor == CENTER)
				y = (pd.height - y) / 2;
			else
				y = pd.height - y - insets.bottom;
			// do layout
			for (int i = 0; i < n; i++) {
				Component c = parent.getComponent(i);
				Dimension d = c.getPreferredSize();
				int x = insets.left;
				int wid = d.width;
				if (alignment == CENTER)
					x = (pd.width - d.width) / 2;
				else if (alignment == RIGHT)
					x = pd.width - d.width - insets.right;
				else if (alignment == BOTH)
					wid = pd.width - insets.left - insets.right;
				c.setBounds(x, y, wid, d.height);
				y += d.height + vgap;
			}
		}
	}

	// -----------------------------------------------------------------------------
	public Dimension minimumLayoutSize(Container parent) {
		return layoutSize(parent, false);
	}

	// -----------------------------------------------------------------------------
	public Dimension preferredLayoutSize(Container parent) {
		return layoutSize(parent, false);
	}

	// ----------------------------------------------------------------------------
	/**
	 * Not used by this class
	 */
	public void addLayoutComponent(String name, Component comp) {
	}

	// -----------------------------------------------------------------------------
	/**
	 * Not used by this class
	 */
	public void removeLayoutComponent(Component comp) {
	}

	// -----------------------------------------------------------------------------
	public String toString() {
		return getClass().getName() + "[vgap=" + vgap + " align=" + alignment
				+ " anchor=" + anchor + "]";
	}
}
```


----------



## b1zarRe (5. Okt 2011)

@André Uhres

Geht das in die richtige Richtung??? Oder wie genau stelle ich nun die Position ein??? Bei PreferedSize verlangt er irgendwie ein Parameter vom Typ Dimension, was mir leider nichts sagt :&

http://www7.pic-upload.de/05.10.11/oq6nzrd46p7.jpg


----------



## André Uhres (6. Okt 2011)

b1zarRe hat gesagt.:


> Bei PreferedSize verlangt er irgendwie ein Parameter vom Typ Dimension, was mir leider nichts sagt



Ja, die "von Java" denken immer um zwei Ecken .
Anstatt
setPreferredSize(width, height)
schreiben sie
setPreferredSize(new Dimension(width, height))
Das muss man einfach so hinnehmen und auch so schreiben.

In Deinem angehängten Bild sehe ich, dass Du "setLocation" aufrufst. Das macht überhaupt keinen Sinn bei der Verwendung von FlowLayout oder irgendeines anderen Layoutmanagers. Der Layoutmanager ist derjenige, der die Position der Komponenten festzulegen hat und nicht Du selbst! (Du kannst natürlich, wenn Du willst, im Buttonpanel auch einen anderen Layoutmanager verwenden, wie hdi vorgeschlagen hat; Flowlayout hat vielleicht den Vorteil des eingebauten Zwischenraums...)

Gruß,
André


```
...
        contents = new JPanel();
        buttonpanel = new JPanel();
        jButton1 = new JButton();
        jButton2 = new JButton();

        buttonpanel.setPreferredSize(new Dimension(120, 100));

        jButton1.setText("jButton1");
        buttonpanel.add(jButton1);

        jButton2.setText("jButton2");
        buttonpanel.add(jButton2);

        contents.add(buttonpanel);

        setContentPane(contents);
...
    private JPanel buttonpanel;
    private JPanel contents;
    private JButton jButton1;
    private JButton jButton2;
...
```


----------



## b1zarRe (6. Okt 2011)

Danke schon mal soweit... Aber die 2 Buttons bei dir im Code einzelnt gezielt zu verschieben geht nicht, oder??


----------



## hdi (7. Okt 2011)

Was meinst du damit? Ein Layout impliziert immer eine gewisse Anordnung. Wenn dir die Anordnung nicht passt, ist das Layout falsch gewählt. Du kannst zwar immer ein bisschen hin und her schieben bzw an der Optik tweaken, entweder direkt über Layout-Constraints (wie zB bei GridBagLayoutConstraints#insets) oder direkt über setMargin(Insets) am Widget. Aber im Endeffekt musst du dein Layout an die gewünschte Anordnung anpassen, und nicht andersherum. 

edit: Oder doch, irgendwie versteh ich den Satz selber nicht  Auf jeden Fall ordnet das FlowLayout die Dinger nebeneinander an. Wenn du das anders haben willst, musst du einen anderen Layout Manager verwenden, so einfach.


----------



## André Uhres (7. Okt 2011)

b1zarRe hat gesagt.:


> die 2 Buttons bei dir im Code einzeln gezielt zu verschieben geht nicht, oder??



Ich bin nicht sicher, was du genau machen willst. Das FlowLayout ordnet die Komponenten in einer oder mehreren Zeilen an, abhängig von ihrer Anzahl und ihren gewünschten Größen, sowie von der Größe des Containers. Zusätzlich kann man noch die Zwischenräume und die Ausrichtung angeben (links, rechts, zentriert). Man kann natürlich auch unsichtbare Labels hinzufügen, wodurch sich andere Komponenten verschieben lassen.

Gruß,
André

```
jButton2.setText("jButton2");
buttonpanel.add(new JLabel("  "));
buttonpanel.add(jButton2);
```


----------



## b1zarRe (7. Okt 2011)

Wie genau funktioniert das mit der Ausrichtung & Zwischenräume???

Ok, ich sehe grade, dass ich mit diesen "Blind" Labels das erreiche was ich eigentlich wollte 
Nur geht das nicht schöner? Das ist ja bisschen unschönes Programmieren oder ist das in der PRaxis so ok??


----------



## bERt0r (7. Okt 2011)

Flow layout ist das falsche, schau mal hier: How to Use BoxLayout (The Java™ Tutorials > Creating a GUI With JFC/Swing > Laying Out Components Within a Container)


----------



## André Uhres (8. Okt 2011)

b1zarRe hat gesagt.:


> Wie genau funktioniert das mit der Ausrichtung & Zwischenräume?


[c]setAlignment(int align)[/c] setzt die Ausrichtung ([c]FlowLayout.LEFT[/c], [c]FlowLayout.RIGHT[/c], [c]FlowLayout.CENTER[/c])
[c]setHgap(int hgap)[/c] setzt den horizontalen Zwischenraum und [c]setVgap(int vgap)[/c] den vertikalen.
Alternativ kann man auch alles im Konstruktor angeben: [c]FlowLayout(int align, int hgap, int vgap) [/c]



b1zarRe hat gesagt.:


> Ok, ich sehe gerade, dass ich mit diesen "Blind" Labels das erreiche was ich eigentlich wollte  Nur geht das nicht schöner? Das ist ja bisschen unschönes Programmieren oder ist das in der Praxis so ok?


Platzhalter können bei Layoutmanagern durchaus ihre Berechtigung haben (das Boxlayout bietet sogar noch zusätzliche "Glue/Rigidarea" Elemente an, die man in den Container einfügen kann).

Gruß,

André


----------



## hdi (8. Okt 2011)

Diese "Blind"-Labels sind in der Tat nicht so dolle. Neben den von André erwähnten Möglichkeiten zur Erzeugung solcher Platzhalter gibt's auch noch


```
Box.createGlue()
```
 und 
	
	
	
	





```
Box.createVertical/HorizontalStrut(int)
```

(es sei denn das hat er damit jetzt gemeint)


----------

