|
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);
}
}