// Author: Graham Freeman. November 2005 // This version: 3rd August 2007 // Copyright (c) Graham Freeman. g-freeman@adfa.edu.au // The author accepts no responsibility for any problems caused by use of // this software. It is supplied free of charge, and usage is unrestricted, // provided this copyright notice remains intact, regardless of how the // software may be modified by other people. // April 2006 release: the algorithm for determining size of the container has // been revised to make it more robust. The first release sometimes gave too // small a container. // July 2008 release: handling of proportional placement has been improved. // There can still be overlapping components and the need to call pack() twice, // but errors in the earlier version in determining container size and // placement have mostly been fixed. import java.awt.*; import java.util.*; /** FormLayout provides a simple means of controlling layout which is * sufficiently powerful to enable many layouts to be achieved with few * programming statements. Four types of constraint are provided: *
* Unlike other layout managers, the FormLayout constructor requires a * parameter, the container it is responsible for. With this layout manager, * components should not be added to the container by the programmer; * instead, calls should * be made to the layout manager indicating how the children are to be * constrained, and the layout manager will itself tell the container of the * children it has gained. The FormLayout object needs to be told of these * constraints with methods: *
| Methods: | Actions: |
| * {@code setLeftAnchor}, {@code setRightAnchor}, * {@code setTopAnchor}, {@code setBottomAnchor} * | Fixed distance from an edge of the container * * |
| * {@code setLeftRelative}, {@code setRightRelative}, * {@code setTopRelative}, {@code setBottomRelative} * | Fixed distance relative to a neighbouring * component * * |
| * {@code setLeftAlign}, {@code setRightAlign}, {@code setTopAlign}, * {@code setBottomAlign} * | One edge aligned with another component * * |
| * {@code setHorizontalAnchor}, {@code setVerticalAnchor} * | Fractional position within the available * width or height * |
* The inspiration for this design came from the form widget in X Windows. * There is also a FormLayout in SWT developed by IBM and maintained now by * Eclipse, which is more sophisticated and flexible, but requires more * lines of code to insert the components. It is also similar to Sun's * SpringLayout, but with fewer features and requiring rather less code. *
* The size of the container is determined from the components placed with * respect to the edges or the other components in the container. Components * placed at a fraction of the width or height of the container are not * considered in determining size; they rely on space being * present as a result of the size of the other components. *
* Relative placement can be made with respect to more than one * neighbour on the left or top side. FormLayout will determine which takes * the greater amount of space and set this position for the component. *
*
Container cpane = getContentPane();
FormLayout form = new FormLayout(cpane);
JLabel lab1 = new JLabel("Name: ") ;
form.setTopAnchor( lab1, 3 );
form.setLeftAnchor( lab1, 4 );
JLabel lab2 = new JLabel("Address: ");
JTextField name = new JTextField(" ",50);
form.setLeftRelative( name, lab1, 3 );
form.setLeftRelative( name, lab2, 3 );
form.setTopAnchor( name, 3 );
form.setLeftAnchor( lab2, 4 );
form.setTopRelative( lab2, name, 3 );
JTextArea addr = new JTextArea(" ",3,50 );
JScrollPane jsp = new JScrollPane( addr,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
form.setLeftAlign( jsp, name );
form.setTopRelative( jsp, name, 3 );
form.setRightAnchor( jsp, 4 );
JLabel lab4 = new JLabel("Adult ");
form.setLeftAlign( lab4, name );
form.setTopRelative( lab4, jsp, 3 );
JTextField adults = new JTextField(" ",3);
form.setLeftRelative( adults, lab4, 3 );
form.setTopRelative( adults, jsp, 3 );
JLabel Ch = new JLabel("Child");
form.setLeftRelative( Ch, adults, 16 );
form.setTopRelative( Ch, jsp, 3 );
JTextField children = new JTextField(" ",3);
form.setLeftRelative( children, Ch, 3 );
form.setTopRelative( children, jsp, 3 );
JLabel Con = new JLabel("Concession");
form.setLeftRelative( Con, children, 16 );
form.setTopRelative( Con, jsp, 3 );
JTextField concess = new JTextField(" ",3);
form.setLeftRelative( concess, Con, 3 );
form.setTopRelative( concess, jsp, 3 );
JButton accept = new JButton("Accept");
form.setHorizontalAnchor( accept, 0.2 );
form.setTopRelative( accept, adults, 3 );
JButton reject = new JButton("Reject");
form.setHorizontalAnchor( reject, 0.5 );
form.setTopAlign( reject, accept );
accept.addActionListener( this );
reject.addActionListener( this );
JButton quit = new JButton("Exit");
form.setHorizontalAnchor( quit, 0.8 );
form.setTopAlign( quit, accept );
form.setBottomAnchor( quit, 5 );
quit.addActionListener( this );
pack();
FormLayout does not have any concept of filling available space, so there are
situations where it will not give as neat appearance as GridBag, such as with
JScrollPanes. There are also occasions after pack() has been called when
FormLayout requests the preferred size of the components within it, and resizes
the container accordingly. If the size reported by a component is incorrect,
FormLayout will have no way of detecting this. It may be necessary to call
pack() a second time in these situations.
*/
public class FormLayout implements LayoutManager
{
//protected ArrayList constrain = new ArrayList();
//protected ArrayList sizepos = new ArrayList();
protected ArrayList
* The size of the constrained component will be requested and placed
* with the constraint.
* @exception RuntimeException is thrown if the parameter does not match
* the container being laid out.
*/
protected Dimension findLayoutSize( Container parent, int which )
{
int maxwid = 0;
int maxht = 0;
// The interface does not allow me to throw an ordinary exception.
if (parent != container)
throw new RuntimeException( "The container in FormLayout is "
+ "inconsistent with the layout manager in the Container.");
if (changedConstraints) orderConstraints();
Insets insets = container.getInsets();
sizepos.clear();
Iterator iter = constrain.iterator();
// Loop over all constraints
while ( iter.hasNext() )
{
// Determine the "placement" object for each of
// the constraints in turn
Constraint c = (Constraint) iter.next();
Placement p = null;
for (int i=0; i
Iteratively go through the constraints, finding any that are
absolute or that depend only on constraints that are already in the
ordered set. Move these over to the end of the ordered list.
If a pass does not move any items from the list and the list
is not empty, there is a circular constraint or a placement relative
to a component which is not within this layout manager.
@exception RuntimeException if there are circular constraints or
dependence on a component not managed by this layout manager.
*/
synchronized protected void orderConstraints()
{
//ArrayList ordered = new ArrayList(constrain.size()+2);
ArrayList