Java tutorial
/* * Copyright (c) Ian F. Darwin, http://www.darwinsys.com/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun's Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun's, and James Gosling's, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.Point; import java.util.StringTokenizer; import java.util.Vector; /** * <p> * RelativeLayout, a Relative Layout Manager for Java J2SE. Mainly for porting * tired old code that uses x,y locations. You really can't just assign x,y * locations to components in Java Java J2SE - it breaks badly when the user * resizes (and you can <em>not</em> mandate that the user can't resize you -- * see any book on UI design for <em>that</em> little discussion -- and can * also look bad due to resolution independance. Symantec Cafe 1.x, for example, * used to spit out unfortunate (and unmaintainable) code like this: * * <pre> * setLayout(null); * setSize(331, 241); * label1 = new Label("Info Applet", Label.CENTER); * add(label1); * label1.setBounds(91, 19, 107, 15); * </pre> * * </p> * <p> * <em>Bleaarrgghh!!!</em> To make it work properly at all resolutions and * survive user-initiated resize actions, change it to * * <pre> * * setLayout(new RelativeLayout(331,241,false); * label1=new Label("Info Applet", Label.CENTER); * add("91,19", label1); * * </pre> * * Note that it's actually <EM>less</EM> work to get it right. Symantec, * Microsoft, and others, please take note! * </p> * * @author Ian Darwin, http://www.darwinsys.com/ */ public class RelativeLayout implements LayoutManager { /** requested absolute width of canvas */ protected int reqWid; /** requested absolute height of canvas */ protected int reqHgt; /** actual size width when laid out */ protected int curWid; /** actual size height when laid out */ protected int curHgt; /** to track Components added by named add form. */ protected Vector curComps = new Vector(); /** * Constructs an RelativeLayout, given original hard-coded size of panel. */ public RelativeLayout(int wid, int ht) { this.reqWid = wid; this.reqHgt = ht; } /** * Called by AWT when the user uses the form add(name, Component). Adds the * specified component with the specified name to the layout. * * @param name * String with location for component c <EM>Note</EM>: the * "name" <EM>must</EM> contain x, y location, ie., <BR> * add("" + 320 + "," + 100, new Button("Quit")); <BR> * or <BR> * add("320,100", new Button("Quit"). <BR> * This adds the Button at x=320, y=100 when the Panel is at its * original full size. * @param c * Component to be added. */ public void addLayoutComponent(String name, Component c) { int x, y; StringTokenizer st = new StringTokenizer(name, ","); x = Integer.parseInt(st.nextToken()); y = Integer.parseInt(st.nextToken()); // System.out.println("Adding: Name " + name +"; obj " + c // + "; x " + x + "; y " + y); Tracker t = new Tracker(x, y, c); curComps.addElement(t); } /** * Called by AWT to lay out the components in the target Container at its * current size. * * @param target * Container whose components are to be laid out. */ public void layoutContainer(Container target) { Dimension targSize = target.getSize(); Insets ins = target.getInsets(); // System.out.println("layoutContainer: size " + targSize); curWid = targSize.width; curHgt = targSize.height; float widRatio = (float) curWid / (float) reqWid; float hgtRatio = (float) curHgt / (float) reqHgt; for (int i = 0; i < curComps.size(); i++) { int px, py, pw, ph; Tracker t = (Tracker) curComps.elementAt(i); Component tc = t.getComponent(); Dimension d = tc.getPreferredSize(); px = ins.right + (int) (t.getRequestedLoc().x * widRatio); py = ins.top + (int) (t.getRequestedLoc().y * hgtRatio); pw = d.width; ph = d.height; // System.out.println("layoutContainer["+i+"]: move " + // tc + " to " + px + ", " + py); tc.setBounds(px, py, pw, ph); } } /** * Called from AWT to calculate the minimum size dimensions for the target * panel given the components in it. But we use our own list of named * insertions, not the list of Components that the container keeps. * * @param target * Container to calculate for */ public Dimension minimumLayoutSize(Container target) { int minw = 0, minh = 0; for (int i = 0; i < curComps.size(); i++) { Tracker t = (Tracker) curComps.elementAt(i); Component tc = t.getComponent(); Dimension d = tc.getMinimumSize(); Point rl = t.getRequestedLoc(); minw = Math.max(minw, rl.x + d.width); minh = Math.max(minh, rl.y + d.height); // System.out.println("minLay, minw = " + minw // + "; minh = " + minh); } return new Dimension(minw, minw); } /** * Called by AWT to compute the preferred size for the target panel given * our list of the components that it contains. * * @param target * Container to calculate for */ public Dimension preferredLayoutSize(Container target) { int prefw = 0, prefh = 0; for (int i = 0; i < curComps.size(); i++) { Tracker t = (Tracker) curComps.elementAt(i); Component tc = t.getComponent(); Dimension d = tc.getMinimumSize(); Point rl = t.getRequestedLoc(); prefw = Math.max(prefw, rl.x + d.width); prefh = Math.max(prefh, rl.y + d.height); // System.out.println("prefLay, prefw = " + // prefw + "; prefh = " + prefh); } return new Dimension(prefw, prefh); } /** * Called by AWT to remove a given component from the layout. * * @param c * Component to be removed */ public void removeLayoutComponent(Component c) { curComps.removeElement(c); } /** * Tracker is a class used only by RelativeLayout, to track the original * "requested" (hard-coded) x,y locations of each Component. */ class Tracker { int absx, absy; Component theComp; /** Construct a tracker item given its location and Component. */ Tracker(int x, int y, Component c) { this.absx = x; this.absy = y; this.theComp = c; } /** Extract the location as a Point. */ public Point getRequestedLoc() { return new Point(absx, absy); } /** Extract the Component from this Tracker. */ public Component getComponent() { return theComp; } } }