tags:

views:

1118

answers:

4
+1  Q: 

XY Layout JAVA

Hi, is there any sort of XY-Layout to Java?

So I can set a Button at the X and Y cordinate and that it is suppose to be that big etc.... Because this border layout and grid and panel thing is driven me crazy. :)

They are flowing every were and getting strecht up. And to make them small you have to put panel in panel in panel in panel ^^,

+2  A: 

If you really want to do this, use

setLayout(null);

on the component you're putting things into, then use

setBounds(x, y, width, height);

to set the absolute coordinates of the elements. Example:

setLayout(null);
JButton myButton = new JButton("Do Stuff");
add(myButton);
myButton.setBounds(30, 30, 100, 30);

However, the resulting GUI will look non-standard, won't be resizable, and if it's of any complexity, will be a pain to maintain.

I know that layouting is frustrating, but in the end you will be better off using a combination of BorderLayouts and FlowLayouts, orGridBagLayout - or an IDE interface builder like Eclipse's or Netbeans'.

Zarkonnen
+3  A: 

The reason components resize is so stuff looks nice whatever size the window is, so Swing discourages straight X-Y position. You might want to have a look at GroupLayout http://java.sun.com/docs/books/tutorial/uiswing/layout/group.html which is designed for GUI builders, and the page mentioned above describes using invisible components to absorb the stretches. eg:layout.setAutoCreateGaps(true);

SpringLayout might also be useful - see the visual guide

If you really want X and Y then set the layout manager to null, and use setLocation() or setBounds(). I REALLY REALLY wouldn't recommend this, but it does work. Have a read of this tutorial

Nick Fortescue
+6  A: 

When setting the container's layout to null (no LayoutManager), you can set the component's bounds individually with component.setBounds(x,y,w,h).

Fixed layouts are in 99% of all cases bad UI design (if your labels, for example, don't get their preferred size you run into mayor problems when your application supports multiple languages), so my advice for you is to rather write a specialized layout manager for your specific needs.

Writing your custom layout manager is quite easy, all you have to do is to be able to calculate the preferred size for a container with given components and your layout, and to do the layout by setting the (calculated) bounds of your components. I got rid of the GridBagLayout and started coding my own layouts long ago, and layouting has never been easier.

Here's an example of a custom layout, that layouts pairs of key and value components:

public class KeyValueLayout implements LayoutManager {

 public static final int KEY_ALIGNMENT_LEFT = 0;

 public static final int KEY_ALIGNMENT_RIGHT = 1;

 private int keyAlignment;

 private int hgap;

 private int vgap;

 public KeyValueLayout () {
  this(KEY_ALIGNMENT_LEFT);
 }

 public KeyValueLayout (int keyAlignment) {
  this(keyAlignment, 5, 5);
 }

 public KeyValueLayout (int hgap, int vgap) {
  this(KEY_ALIGNMENT_LEFT, hgap, vgap);
 }

 public KeyValueLayout (int keyAlignment, int hgap, int vgap) {
  if (keyAlignment != KEY_ALIGNMENT_LEFT && keyAlignment != KEY_ALIGNMENT_RIGHT)
   throw new IllegalArgumentException(
    "Invalid key alignment constraints. Use either KEY_ALIGNMENT_LEFT or KEY_ALIGNMENT_RIGHT");

  this.keyAlignment = keyAlignment;
  this.hgap = hgap;
  this.vgap = vgap;
 }

 public void addLayoutComponent (String name, Component comp) {
 }

 public void addLayoutComponent (Component comp, Object constraints) {
 }

 public void removeLayoutComponent (Component comp) {
 }

 public void layoutContainer (Container parent) {
  Rectangle canvas = getLayoutCanvas(parent);
  int ypos = canvas.y;
  int preferredKeyWidth = getPreferredKeyWidth(parent);

  for (Iterator iter = new ComponentIterator(parent); iter.hasNext();) {
   Component key = (Component) iter.next();
   Component value = iter.hasNext() ? (Component) iter.next() : null;
   int xpos = canvas.x;
   int preferredHeight = Math.max(key.getPreferredSize().height,
    value != null ? value.getPreferredSize().height : 0);

   if (keyAlignment == KEY_ALIGNMENT_LEFT)
    key.setBounds(xpos, ypos, key.getPreferredSize().width, key.getPreferredSize().height);
   else
    key.setBounds(xpos + preferredKeyWidth - key.getPreferredSize().width, ypos,
     key.getPreferredSize().width, key.getPreferredSize().height);

   xpos += preferredKeyWidth + hgap;
   if (value != null)
    value.setBounds(xpos, ypos, canvas.x + canvas.width - xpos, preferredHeight);
   ypos += preferredHeight + vgap;
  }
 }

 public Dimension minimumLayoutSize (Container parent) {
  int preferredKeyWidth = getPreferredKeyWidth(parent);
  int minimumValueWidth = 0;
  int minimumHeight = 0;
  int lines = 0;
  for (Iterator iter = new ComponentIterator(parent); iter.hasNext();) {
   lines++;
   Component key = (Component) iter.next();
   Component value = iter.hasNext() ? (Component) iter.next() : null;
   minimumHeight += Math.max(key.getPreferredSize().height, value != null ? value.getMinimumSize().height : 0);
   minimumValueWidth = Math.max(minimumValueWidth, value != null ? value.getMinimumSize().width : 0);
  }

  Insets insets = parent.getInsets();
  int minimumWidth = insets.left + preferredKeyWidth + hgap + minimumValueWidth + insets.right;
  minimumHeight += insets.top + insets.bottom;
  if (lines > 0)
   minimumHeight += (lines - 1) * vgap;

  return new Dimension(minimumWidth, minimumHeight);
 }

 public Dimension preferredLayoutSize (Container parent) {
  int preferredKeyWidth = getPreferredKeyWidth(parent);
  int preferredValueWidth = 0;
  int preferredHeight = 0;
  int lines = 0;
  for (Iterator iter = new ComponentIterator(parent); iter.hasNext();) {
   lines++;
   Component key = (Component) iter.next();
   Component value = iter.hasNext() ? (Component) iter.next() : null;

   preferredHeight += Math.max(key.getPreferredSize().height, value != null ? value.getPreferredSize().height
    : 0);
   preferredValueWidth = Math.max(preferredValueWidth, value != null ? value.getPreferredSize().width : 0);
  }

  Insets insets = parent.getInsets();
  int preferredWidth = insets.left + preferredKeyWidth + hgap + preferredValueWidth + insets.right;
  preferredHeight += insets.top + insets.bottom;
  if (lines > 0)
   preferredHeight += (lines - 1) * vgap;

  return new Dimension(preferredWidth, preferredHeight);
 }

 public Dimension maximumLayoutSize (Container target) {
  return preferredLayoutSize(target);
 }

 private int getPreferredKeyWidth (Container parent) {
  int preferredWidth = 0;
  for (Iterator iter = new ComponentIterator(parent); iter.hasNext();) {
   Component key = (Component) iter.next();
   if (iter.hasNext())
    iter.next();

   preferredWidth = Math.max(preferredWidth, key.getPreferredSize().width);
  }

  return preferredWidth;
 }

 private Rectangle getLayoutCanvas (Container parent) {
  Insets insets = parent.getInsets();
  int x = insets.left;
  int y = insets.top;

  int width = parent.getSize().width - insets.left - insets.right;
  int height = parent.getSize().height - insets.top - insets.bottom;

  return new Rectangle(x, y, width, height);
 }

 private class ComponentIterator implements Iterator {

  private Container container;

  private int index = 0;

  public ComponentIterator (Container container) {
   this.container = container;
  }

  public boolean hasNext () {
   return index < container.getComponentCount();
  }

  public Object next () {
   return container.getComponent(index++);
  }

  public void remove () {
  }
 }
}

Just set the layout and add alternatingly labels and value components. It's easy to use, especially compared to GridBagLayout or nested panels with custom layouts.

Peter Walser
+1  A: 

This doesn't answer your specific question, but as well as agreeing with the other comments, have a look at MiG Layout. I have been equally frustrated with layouts as a Swing newbie, but this has helped a lot.

Miles D