Custom GUI Layout
in Java |
Prof. David Bernstein |
Computer Science Department |
bernstdh@jmu.edu |
package slides; import java.awt.*; import java.util.*; /** * A LayoutManager that treats each component in a container * as if it is on a page of a flip chart. * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class FlipChartLayout implements LayoutManager { private LinkedList components; private static final int MINIMUM_SIZE = 0; private static final int PREFERRED_SIZE = 1; /** * Default Constructor */ public FlipChartLayout() { components = new LinkedList(); } /** * Adds the specified component to this LayoutManager. * (Required by LayoutManager) * * @param name The name of the component (not used) * @param comp The component to be added */ public void addLayoutComponent(String name, Component comp) { synchronized (comp.getTreeLock()) { if (components.isEmpty()) comp.setVisible(true); else comp.setVisible(false); components.addLast(comp); } } /** * Flips the pages backward by one * * @param parent The parent container */ public void backward(Container parent) { Component comp; synchronized (parent.getTreeLock()) { // Throw an Exception if the parent isn't using this layout checkLayout(parent); if (!components.isEmpty()) { comp = (Component)components.getFirst(); comp.setVisible(false); comp = (Component)components.removeLast(); comp.setVisible(true); components.addFirst(comp); parent.validate(); } } } /** * Determines either maximum (of each dimension) * of the components in the container. * * @param parent The name of the parent container * @return The preferred size */ private Dimension calculateLayoutSize(Container parent, int type) { Component comp; Dimension d; Insets insets; int w, h; Iterator iter; synchronized (parent.getTreeLock()) { // Throw an Exception if the parent isn't using this layout checkLayout(parent); // Initialize the width and height w = 0; h = 0; // Get the insets (i.e., unused space) for the parent insets = parent.getInsets(); // Calculate the maximum (along each dimension) iter = components.iterator(); while (iter.hasNext()) { comp = (Component)iter.next(); if (type == PREFERRED_SIZE) d = comp.getPreferredSize(); else d = comp.getMinimumSize(); if (d.width > w) w = d.width; if (d.height > h) h = d.height; } return new Dimension(insets.left + insets.right + w, insets.top + insets.bottom + h); } } /** * Make sure that the parent is actually using this * FlipChartLayout * * @param parent The parent container */ private void checkLayout(Container parent) { if ((parent == null) || (parent.getLayout() != this)) { throw new IllegalArgumentException("The parent container "+ "is not using a "+ "FlipChartLayout"); } } /** * Flips the pages forward by one * * @param parent The parent container */ public void forward(Container parent) { Component comp; synchronized (parent.getTreeLock()) { // Throw an Exception if the parent isn't using this layout checkLayout(parent); if (!components.isEmpty()) { comp = (Component)components.removeFirst(); comp.setVisible(false); components.addLast(comp); comp = (Component)components.getFirst(); comp.setVisible(true); parent.validate(); } } } /** * Gets the current front/first page * * @param parent The parent container */ public Component getFirst(Container parent) { Component comp; synchronized (parent.getTreeLock()) { // Throw an Exception if the parent isn't using this layout checkLayout(parent); comp = null; if (!components.isEmpty()) { comp = (Component)components.getFirst(); } return comp; } } /** * Lays out the specified container. * (Required by LayoutManager) * * Specifically, the first component is reshaped * to be the size of the container, minus space for surrounding * insets. * * @param parent The parent container */ public void layoutContainer(Container parent) { Component first; Dimension d; Insets insets; synchronized (parent.getTreeLock()) { // Throw an Exception if the parent isn't using this layout checkLayout(parent); if (!components.isEmpty()) { d = parent.getSize(); insets = parent.getInsets(); first = (Component)components.getFirst(); first.setBounds(insets.left, insets.top, d.width - (insets.left + insets.right), d.height - (insets.top + insets.bottom)); first.setVisible(true); } } } /** * Calculates the minimum size for the specified panel. * (Required by LayoutManager) * * In this case, it is simply the maximum of the minimum sizes * of the "pages" of the FlipChart. * * @param parent The name of the parent container * @return The preferred size */ public Dimension minimumLayoutSize(Container parent) { return calculateLayoutSize(parent, MINIMUM_SIZE); } /** * Determines the preferred size of the container. * (Required by LayoutManager) * * In this case, it is simply the maximum of the preferred sizes * of the "pages" of the FlipChart. * * @param parent The name of the parent container * @return The preferred size */ public Dimension preferredLayoutSize(Container parent) { return calculateLayoutSize(parent, PREFERRED_SIZE); } /** * Removes the specified component from the layout. * (Required by LayoutManager) * * @param comp The component to be removed */ public void removeLayoutComponent(Component comp) { Component first; int index; synchronized (comp.getTreeLock()) { if (!components.isEmpty()) { first = (Component)components.getFirst(); if (first == comp) { comp.setVisible(false); components.removeFirst(); if (!components.isEmpty()) { first = (Component)components.getFirst(); first.setVisible(true); } } else { components.remove(comp); } } } } }
package slides; import java.awt.*; import java.util.*; /** * A LayoutManager that can be used for slide * presentations and outlines * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class SlideLayout implements LayoutManager { private Font[] fonts; private Hashtable constraints; private int numLevels; private int[] indents, vSpaces; private static final int indentWidthInPixels = 40; private static final int lineHeightInPixels = 50; public static final String CENTER = "CENTER"; public static final String LEVEL0 = "LEVEL0"; public static final String LEVEL1 = "LEVEL1"; public static final String LEVEL2 = "LEVEL2"; /** * Default constructor */ public SlideLayout() { int i, iSize, fSize; constraints = new Hashtable(); numLevels = 5; indents = new int[numLevels]; vSpaces = new int[numLevels]; fonts = new Font[numLevels]; fSize = 24; iSize = 0; for (i=0; i < numLevels; i++) { indents[i] = iSize; fonts[i] = new Font("Sans Serif", Font.PLAIN, fSize); vSpaces[i] = lineHeightInPixels / 5; fSize -= 3; iSize += indentWidthInPixels; } vSpaces[0] = lineHeightInPixels; } /** * Adds the specified component with the specified "constraint" * to the layout (Required by LayoutManager) * * @param constraint The constraint (e.g., "LEVEL0" or "CENTER") * @param comp The component */ public void addLayoutComponent(String constraint, Component comp) { synchronized (comp.getTreeLock()) { constraints.put(comp, constraint); } } /** * Lays out the container in the specified panel * (Required by LayoutManager) * * @param The Container to layout */ public void layoutContainer(Container parent) { Component[] e; Component comp; Dimension dComp, dParent; int i, level, x, y; String constraint; synchronized (parent.getTreeLock()) { dParent = parent.getSize(); y = 0; e = parent.getComponents(); for (i=0; i < e.length; i++) { comp = e[i]; constraint = (String)constraints.get(comp); if (constraint.equals(CENTER)) { y += vSpaces[2]; dComp = comp.getSize(); x = dParent.width/2 - dComp.width/2; } else { if (constraint.equals(LEVEL0)) level = 0; else if (constraint.equals(LEVEL1)) level = 1; else if (constraint.equals(LEVEL2)) level = 2; else level = 2; x = indents[level]; y += vSpaces[level]; comp.setFont(fonts[level]); } locateComponent(comp, x, y); // Update the vertical position dComp = comp.getSize(); y += dComp.height; } } } /** * Set the location of a component * * @param comp The component * @param x The horizontal location * @param y The vertical location */ protected void locateComponent(Component comp, int x, int y) { Dimension dComp; // Set the width of the Component dComp = comp.getPreferredSize(); comp.setSize(dComp); // Invalidate any cached information used to layout // the Component comp.invalidate(); // Set the location of the Component comp.setLocation(x, y); // Validate the component (i.e., layout the component) comp.validate(); } /** * Calculates the minimum size dimensions for the specified * panel given the components in the specified parent container * (Required by LayoutManager) * * @param parent The Container * @return The minimum size */ public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } /** * Calculates the preferred size dimensions for the specified * panel given the components in the specified parent container * (Required by LayoutManager) * * @param parent The Container * @return The preferred size */ public Dimension preferredLayoutSize(Container parent) { Component[] components; Dimension d, parentD; synchronized (parent.getTreeLock()) { // Note: Should worry about insets d = new Dimension(0,0); components = parent.getComponents(); if ((components != null) && (components.length != 0)) { parentD = parent.getSize(); d.width = parentD.width; d.height = components.length * lineHeightInPixels; if (d.height < parentD.height) d.height = parentD.height; } return d; } } /** * Removes the specified component from the layout * (Required by LayoutManager) * * @param comp The Component to remove */ public void removeLayoutComponent(Component comp) { constraints.remove(comp); } }
package slides; import java.applet.*; import java.awt.*; import javax.swing.*; /** * A slide (for use in a slide presentation) * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class Slide extends JPanel { private SlideLayout layout; /** * Default Constructor * * Note: This is used for a slide that does not * have a title */ public Slide() { this(null); } /** * Explicit Value Constructor * * @param title The title of the slide */ public Slide(String title) { super(); setBackground(SlidePresentation.BACKGROUND); setForeground(SlidePresentation.FOREGROUND); setName(title); layout = new SlideLayout(); setLayout(layout); } /** * Add a "generic" bullet * * @param comp The component to use * @param level The indentation level */ public void addBullet(Component comp, String level) { comp.setForeground(getForeground()); comp.setBackground(getBackground()); add(level, comp); } /** * Add a text bullet * * @param text The text to use * @param level The indentation level */ public Component addBullet(String text, String level) { Label b; b = new Label(text); b.setForeground(getForeground()); b.setBackground(getBackground()); add(level, b); return b; } /** * Set the visibility of this component * * @param ok The visibility (true for visible) */ public void setVisible(boolean ok) { Component[] c; int i; c = getComponents(); for (i=0; i < c.length; i++) c[i].setVisible(ok); } }
package slides; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * The button panel for a slide presentation * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class ButtonPanel extends JPanel { private JButton backwardB, forwardB; private static final Insets margin = new Insets(0,0,0,0); /** * Default constructor */ public ButtonPanel() { backwardB = createButton("backward"); forwardB = createButton("forward"); performLayout(); backwardB.setEnabled(true); forwardB.setEnabled(true); } /** * Add an ActionListener * * @param al The listener */ public void addActionListener(ActionListener al) { backwardB.addActionListener(al); forwardB.addActionListener(al); } /** * Create a button * * @param prefix The button's identifier * @return The button */ private JButton createButton(String prefix) { JButton b; b = new JButton(); setupButton(b, prefix); return b; } /** * Set-up a button * * @param b The button * @param prefix The button's identifier */ private void setupButton(AbstractButton b, String prefix) { ImageIcon icon; icon = new ImageIcon(prefix+"out.gif"); b.setIcon(icon); icon = new ImageIcon(prefix+"disabled.gif"); b.setDisabledIcon(icon); b.setMargin(margin); b.setBorderPainted(false); b.setFocusPainted(false); b.setRolloverEnabled(false); b.setActionCommand(prefix); b.setBackground(null); } /** * Layout this component */ private void performLayout() { setBackground(null); setLayout(new FlowLayout()); add(backwardB); add(forwardB); } }
package slides; import java.awt.*; import javax.swing.*; /** * A panel containing slide titles * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class TitlePanel extends JPanel { private Color highlight; private String text; /** * Default constructor */ public TitlePanel() { this(null); } /** * Explicit value constructor * * @param text The text in the title */ public TitlePanel(String text) { this.text = text; setBackground(null); setForeground(null); setHighlight(Color.white); } /** * Get the highlight color * * @return The highlight color */ public Color getHighlight() { return highlight; } /** * Get the minimum size of this component * * @return The minimum size */ public Dimension getMinimumSize() { return getPreferredSize(); } /** * Get the preferred size of this component * * @return The preferred size */ public Dimension getPreferredSize() { FontMetrics fm; int h, w; fm = getFontMetrics(getFont()); h = fm.getHeight()+fm.getMaxDescent()+20; w = fm.stringWidth(text) * 2; return new Dimension(w, h); } /** * Paint this component * * @param g The Graphics context to use */ public void paint(Graphics g) { Dimension d; FontMetrics fm; int bars, barHeight, barSpace; int barTop, barThickness, barWidth; int descent, h, i, middle, w, x; super.paint(g); barSpace = 6; barThickness = 3; bars = 5; if (text != null) { g.setFont(getFont()); fm = g.getFontMetrics(); d = getSize(); h = fm.getHeight(); middle = d.height/2; descent = fm.getMaxDescent(); barWidth = d.width*7/10; barHeight = descent+h; barTop = middle-h/2-descent/2; g.setColor(getHighlight()); g.fillRect(0, barTop, barWidth, barHeight); x = barWidth; for (i=0; i < bars; i++) { x += barSpace; g.fillRect(x, barTop, barThickness, barHeight); x += barThickness; } x = 5; g.setColor(getForeground()); g.drawString(text, x, middle+h/2-descent/2); } } /** * Set the highlight color * * @param highlight The highlight color */ public void setHighlight(Color highlight) { this.highlight = highlight; } /** * Set the title text */ public void setText(String text) { this.text = text; repaint(); } }
package slides; import java.awt.*; import java.awt.event.*; import javax.swing.*; /** * A container for a slide presentation * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class SlidePresentation extends JPanel implements ActionListener { protected ButtonPanel buttonP; protected FlipChartLayout layout; protected Panel slidePanel; protected TitlePanel titleP; public static final Color BACKGROUND = Color.black; public static final Color FOREGROUND = Color.white; public static final Color TITLE = Color.yellow; /** * Explicit value constructor * * @param slides The array of slides */ public SlidePresentation(Component[] slides) { super(); slidePanel = new Panel(); buttonP = new ButtonPanel(); layout = new FlipChartLayout(); titleP = new TitlePanel(" "); performLayout(slides); buttonP.addActionListener(this); showTitle(); } /** * Handle actionPerformed events (required by ActionListener) * * @param evt The event */ public void actionPerformed(ActionEvent evt) { Object source; String ac; ac = evt.getActionCommand(); if (ac.equals("forward")) forward(); else if (ac.equals("backward")) backward(); showTitle(); } /** * Move one slide backward */ protected void backward() { layout.backward(slidePanel); showTitle(); } /** * Move one slide forward */ protected void forward() { layout.forward(slidePanel); showTitle(); } /** * Layout this component */ protected void performLayout(Component[] slides) { ImageIcon icon; int i; JPanel bottomP, centerP, tmpP; JLabel keyboardP; setBackground(BACKGROUND); setForeground(FOREGROUND); titleP.setHighlight(TITLE); titleP.setForeground(BACKGROUND); titleP.setBackground(BACKGROUND); setLayout(new BorderLayout()); slidePanel.setLayout(layout); for (i=0; i < slides.length; i++) { slidePanel.add(slides[i], "Slide"+i); } add(slidePanel, BorderLayout.CENTER); bottomP = new JPanel(); bottomP.setLayout(new BorderLayout()); tmpP = new JPanel(); tmpP.setBackground(BACKGROUND); tmpP.setLayout(new GridLayout(2,1)); tmpP.add(new JLabel(" ")); tmpP.add(buttonP); bottomP.add(tmpP, BorderLayout.WEST); icon = new ImageIcon("keyboard.gif"); keyboardP = new JLabel(icon); bottomP.add(keyboardP, BorderLayout.EAST); bottomP.add(new JLabel(" "), BorderLayout.CENTER); bottomP.setBackground(Color.black); add(bottomP, BorderLayout.SOUTH); titleP.setFont(new Font("Sans Serif", Font.BOLD, 24)); add(titleP, BorderLayout.NORTH); } /** * Show the title associated with the first/front * slide */ protected void showTitle() { Slide first; first = (Slide)layout.getFirst(slidePanel); if (first != null) { titleP.setText(first.getName()); } } }
import java.awt.*; import javax.swing.*; import gui.*; import slides.Slide; import slides.SlideLayout; import slides.SlidePresentation; /** * The driver for a slide presentation * * @author Prof. David Bernstein, James Madison University * @version 1.0 */ public class Driver { /** * The entry point for the application * * @param args The command-line arguments */ public static void main(String[] args) { CloseableFrame f; Container contentPane; ImageIcon icon; JLabel image; JPanel p; Slide temp; Slide[] slides; f = new CloseableFrame(); contentPane = f.getContentPane(); contentPane.setLayout(new BorderLayout()); slides = new Slide[3]; // Slide 0 temp = new Slide("About the CS Department at JMU"); icon = new ImageIcon("chip.gif"); image = new JLabel(icon); image.setBackground(Color.black); temp.addBullet("Computing is at the core of many "+ "advances, including:", SlideLayout.LEVEL0); temp.addBullet("The Internet", SlideLayout.LEVEL1); temp.addBullet("Mobile Telecommunications", SlideLayout.LEVEL1); temp.addBullet("Interactive TV", SlideLayout.LEVEL1); temp.addBullet("Intelligent Devices", SlideLayout.LEVEL1); temp.addBullet(image, SlideLayout.CENTER); temp.addBullet("The CS Department at JMU teaches students to:", SlideLayout.LEVEL0); temp.addBullet("Improve existing uses of computers", SlideLayout.LEVEL1); temp.addBullet("Develop new uses of computers", SlideLayout.LEVEL1); slides[0] = temp; // Slide 1 temp = new Slide("Special Programs"); icon = new ImageIcon("acm.gif"); image = new JLabel(icon); image.setBackground(Color.black); temp.addBullet("Honors Program", SlideLayout.LEVEL0); temp.addBullet("Internship Program", SlideLayout.LEVEL0); temp.addBullet("Interdisciplinary Minors", SlideLayout.LEVEL0); temp.addBullet("Health Information Systems", SlideLayout.LEVEL1); temp.addBullet("Telecommunications", SlideLayout.LEVEL1); temp.addBullet("Various Clubs and Organizations", SlideLayout.LEVEL0); temp.addBullet(image, SlideLayout.LEVEL1); temp.addBullet("Independent Studies and Directed Research", SlideLayout.LEVEL0); slides[1] = temp; // Slide 2 temp = new Slide("Career Opportunities"); temp.addBullet("Graduates typically become:", SlideLayout.LEVEL0); temp.addBullet("Programmers", SlideLayout.LEVEL1); temp.addBullet("Software Engineers", SlideLayout.LEVEL1); temp.addBullet("Recent graduates have worked for:", SlideLayout.LEVEL0); temp.addBullet("AT&T", SlideLayout.LEVEL1); temp.addBullet("Capital One", SlideLayout.LEVEL1); temp.addBullet("GTE", SlideLayout.LEVEL1); temp.addBullet("IBM", SlideLayout.LEVEL1); slides[2] = temp; contentPane.add(new SlidePresentation(slides)); //contentPane.add(new SlideShow(slides)); f.setSize(600,800); f.show(); f.setBackground(Color.black); f.setForeground(Color.white); } }