What is your favorite layout?

Here is an early version of EasyLayout. I’m still changing a few things around.

Also, you need to have the code of Combo and EasyPanel to make it work. But those 2 class are pretty short.

public class EasyLayout implements LayoutManager{
	
	public static final int HORIZONTAL = 0;
	public static final int VERTICAL = 1;
	
	private int type;
	
	public EasyLayout(int type){
		this.type = type;
	}

	@Override
	public void addLayoutComponent(String name, Component comp) {
		//Not used
	}

	@Override
	public void layoutContainer(Container parent) {
		if(parent instanceof EasyPanel){
			EasyPanel panel = (EasyPanel)parent;
			ArrayList<Combo> list = panel.getComboList();
			if(type == HORIZONTAL){
				horizontalLayout(list, panel);
			}else if(type == VERTICAL){
				verticalLayout(list, panel);
			}
		}
	}
	
	private void horizontalLayout(ArrayList<Combo> list, EasyPanel parent){
		int currentPos = 0;
		
		for(int i=0; i<list.size(); i++){
			Combo combo = list.get(i);
			
			if(combo.getType() == Combo.Normal){
				Component comp = combo.getComponent();
				int width = (int)comp.getPreferredSize().getWidth();
				comp.setLocation(currentPos, 0);
				comp.setSize(width, parent.getHeight());
				currentPos += width;
			}else if(combo.getType() == Combo.Space){
				Component comp = combo.getComponent();
				int width = (Integer)combo.getValue();
				comp.setLocation(currentPos, 0);
				comp.setSize(width, parent.getHeight());
				currentPos += width;
			}else if(combo.getType() == Combo.Fill){
				Component comp = combo.getComponent();
				double fillPercent = ((Double)combo.getValue())/getTotalFillValue(list);
				int width = (int) (getTotalFillSize(list, parent)*fillPercent);
				comp.setLocation(currentPos, 0);
				comp.setSize(width, parent.getHeight());
				currentPos += width;
			}else{
				//We have a problem
			}
		}
	}
	
	private void verticalLayout(ArrayList<Combo> list, EasyPanel parent){
		int currentPos = 0;
		
		for(int i=0; i<list.size(); i++){
			Combo combo = list.get(i);
			
			if(combo.getType() == Combo.Normal){
				Component comp = combo.getComponent();
				int height = (int)comp.getPreferredSize().getHeight();
				comp.setLocation(0, currentPos);
				comp.setSize(parent.getWidth(), height);
				currentPos += height;
			}else if(combo.getType() == Combo.Space){
				Component comp = combo.getComponent();
				int height = (Integer)combo.getValue();
				comp.setLocation(0, currentPos);
				comp.setSize(parent.getWidth(), height);
				currentPos += height;
			}else if(combo.getType() == Combo.Fill){
				Component comp = combo.getComponent();
				double fillPercent = ((Double)combo.getValue())/getTotalFillValue(list);
				int height = (int) (getTotalFillSize(list, parent)*fillPercent);
				comp.setLocation(0, currentPos);
				comp.setSize(parent.getWidth(), height);
				currentPos += height;
			}else{
				//We have a problem
			}
		}
	}
	
	private int getTotalFillSize(ArrayList<Combo> list, EasyPanel parent){
		int result = 0;
		
		if(type == HORIZONTAL){
			result = parent.getWidth()-getTotalFixedSize(list);
		}else if(type == VERTICAL){
			result = parent.getHeight()-getTotalFixedSize(list);
		}
		
		if(result < 0){
			result = 0;
		}
		
		return result;
	}
	
	private double getTotalFillValue(ArrayList<Combo> list){
		double result = 0;
		
		for(int i=0; i<list.size(); i++){
			Combo combo = list.get(i);
			
			if(combo.getType() == Combo.Fill){
				result += (Double)combo.getValue();
			}
		}
		
		return result;
	}
	
	public int getTotalFixedSize(ArrayList<Combo> list){
		int result = 0;
		
		for(int i=0; i<list.size(); i++){
			Combo combo = list.get(i);
			
			if(combo.getType() == Combo.Normal){
				Component comp = combo.getComponent();
				if(type == HORIZONTAL){
					result += (int)comp.getPreferredSize().getWidth();
				}else if(type == VERTICAL){
					result += (int)comp.getPreferredSize().getHeight();
				}
			}else if(combo.getType() == Combo.Space){
				result += (Integer)combo.getValue();
			}
		}
		
		return result;
	}
	
	public int getTotalPrefSize(ArrayList<Combo> list){
		int result = 0;
		
		for(int i=0; i<list.size(); i++){
			Combo combo = list.get(i);
			
			if(combo.getType() == Combo.Normal){
				Component comp = combo.getComponent();
				if(type == HORIZONTAL){
					result += (int)comp.getPreferredSize().getWidth();
				}else if(type == VERTICAL){
					result += (int)comp.getPreferredSize().getHeight();
				}
			}else if(combo.getType() == Combo.Space){
				result += (Integer)combo.getValue();
			}else if(combo.getType() == Combo.Fill){
				Component comp = combo.getComponent();
				if(type == HORIZONTAL){
					result += (int)comp.getPreferredSize().getWidth();
				}else if(type == VERTICAL){
					result += (int)comp.getPreferredSize().getHeight();
				}
			}
		}
		
		return result;
	}

	@Override
	public Dimension minimumLayoutSize(Container parent) {
		//Not used
		return new Dimension(10, 10);
	}

	@Override
	public Dimension preferredLayoutSize(Container parent) {
		if(type == HORIZONTAL){
			EasyPanel panel = (EasyPanel) parent;
			ArrayList<Combo> list = panel.getComboList();
			int width = getTotalPrefSize(list);
			int height = 0;
			for(Combo combo : list){
				Component comp = combo.getComponent();
				int prefHeight = (int) comp.getPreferredSize().getHeight();
				if(prefHeight > height){
					height = prefHeight;
				}
			}
			return new Dimension(width, height);
		}
		if(type == VERTICAL){
			EasyPanel panel = (EasyPanel) parent;
			ArrayList<Combo> list = panel.getComboList();
			int width = 0;
			int height = getTotalPrefSize(list);
			for(Combo combo : list){
				Component comp = combo.getComponent();
				int prefWidth = (int) comp.getPreferredSize().getWidth();
				if(prefWidth > width){
					width = prefWidth;
				}
			}
			return new Dimension(width, height);
		}
		//Not used
		return new Dimension(10, 10);
	}

	@Override
	public void removeLayoutComponent(Component comp) {
		//Not used
	}

}
  1. Yes, you would just put the layout in a JFrame. I didn’t think it mattered.
  2. I used a nested table to simplify. It could be rewritten a different way so the text edit and button are in the same row. Or you could add negative padding to the button.
  3. Sure, that would be done with padding on the table (goes around all cells).
  4. TableLayout wants to keep widgets from overlapping. However, it has the notion of a “stack” which is a widget that lays out its children to be the same size as the stack widget. This could be used to get the behavior you want, but it’s a bit of an odd layout.
  5. Not sure what you mean by interact? You create a Table, register any widgets you want to use in the DSL by name, then give it the DSL text or file.

It’s already in a post below.

Do you mean the source code for my EasyLayout class?
[/quote]
I meant you should post how the code looks for the layouts in your screenshot, but I found it now. Somehow I missed a couple posts in this thread!

For your API, you might think about making it easier to specify space between widgets. I do this by having separate space and padding. Padding is addtive, eg a cell with 10 padding next to one with 20 padding = 30 padding. Spacing isn’t, eg a cell with 10 spacing next to one with 20 spacing = 20 padding (the larger). Next I allow you to set the default cell properties for all in the table, all in specific columns, all in a row, and then the cell properties themselves. They are applied in that order, so later properties can override those set higher up. This mean setting spacing to 10 on the default cell properties makes all cells 10 pixels apart, then I only have to tweak it for cells that vary from that.

If I am creating an EasyPanel, why do I also have to set the layout? Could save a line of code.

I forgot to show the TableLayout Java API for your layouts screenshot. Here:

http://dl.dropbox.com/u/16471407/EasyLayout.PNG

First window:


Table table = new Table();
table.defaults().space(6);
table.add(findLabel).top();

Table centerTable = new Table();
table.add(centerTable);
centerTable.defaults().left().space(6);
centerTable.add(findEdit).colspan(2).fill();
centerTable.row();
centerTable.add(matchCaseCheckbox);
centerTable.add(wrapCheckbox);
centerTable.row();
centerTable.add(wholeWordsCheckbox);
centerTable.add(backwardsCheckbox);

Table rightTable = new Table();
table.add(rightTable);
rightTable.defaults().space(6);
rightTable.add(findButton);
rightTable.row();
rightTable.add(cancelButton);

Second window:


Table table = new Table();
table.defaults().space(6).right();
table.columnDefaults(1).expandX().fill();
table.add(nameLabel);
table.add(nameEdit);
table.row();
table.add(faxLabel);
table.add(faxEdit);
table.row();
table.add(emailLabel);
table.add(emailEdit);
table.row();
table.add(addressLabel);
table.add(addressEdit);

Third window:


Table table = new Table();
table.defaults().expandX().left();
table.add(button);
table.row();
table.add(button).padLeft("20%");
table.row();
table.add(button).padLeft("40%");
table.row();
table.add(button).padLeft("60%");
table.row();
table.add(button).padLeft("80%");

[quote=“Nate,post:22,topic:37761”]
If I am creating an EasyPanel, why do I also have to set the layout? Could save a line of code.

[quote/]

By default, the layout in EasyPanel is EasyLayout.HORIZONTAL. The thing is that there is 2 modes in EasyLayout : Horizontal or Vertical. So you have to chose which layout you want. Also, you can put different layout into EasyPanel for example; GridLayout. You can create an equivalent to GridLayout with EasyLayout but it requires more line of code.

My layout is meant to be a replacement to BoxLayout and BorderLayout. Only that and nothing more. Everyone using a few nested BorderLayout to put thing in a column or a row could use 1 instance of EasyLayout to achieve the same think with fewer panel and fewer line of code. For the case of BoxLayout, I just suppose it’s easier to use since I never spent much time to really understand BoxLayout, but I know they are practically the same thing with a few difference. (I don’t think you could do the diagonal layout with box layout for example)

Don’t ditch the FlowLayout man, it is my favorite tool for making components not stretch out to use all available space and it is an easy way to align components otherwise. I tend to use a combination of BorderLayout (possibly nested) and FlowLayout the most, GridLayout and BoxLayout have their occasional use only.

What I missed in FlowLayout was the ability to align vertically, and of course I wasn’t the only one:

http://www.java2s.com/Code/Java/Swing-JFC/AverticallayoutmanagersimilartojavaawtFlowLayout.htm

This can be used as a replacement for FlowLayout and can also align to top and bottom. Love it.

My games always have a fixed-size frame and therefore I always just use the ‘null’-layout and set the dimension and coordinates for each component manually.
It’s easy and straightforward. I’m surprised that apparently nobody else does it this way.

Fair enough. It’s just my opinion and I haven’t tried all the layout managers that exist. But I still think MigLayout is much better than the official ones. I don’t find it that complex because I can solve most of the problems looking at the quick start guide or a quick look at the cheat sheet.

Your system looks cool but seems to be a lot more than just a layout manager. Not sure I want to go there. Besides, I’ve got my own property system that use to bind to swing components.

I used to use the NetBeans editor but I found it difficult to use and I could not get it to do what I wanted. And I don’t like being dependent on NetBeans when changing a layout. And the code it generates are horrendous and impossible to read.

Because you never know the real size of the components. It depends on many things like look and feel, the font used and internationalization. Might work in certain games but not in general.

For applications, fixed size normally is often not very friendly.

Which is why I often wonder why MS doesn’t get this and update the many places in Windows where you can’t resize windows! My personal favorite is the dialog to edit an environment variable value.