/*
* Copyright (c) 2000 David Flanagan. All rights reserved. This code is from the
* book Java Examples in a Nutshell, 2nd Edition. It is provided AS-IS, WITHOUT
* ANY WARRANTY either expressed or implied. You may study, use, and modify it
* for any non-commercial purpose. You may distribute it non-commercially as
* long as you retain this notice. For a commercial use license, or to purchase
* the book (recommended), visit http://www.davidflanagan.com/javaexamples2.
*/
import java.applet.Applet;
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Panel;
import java.awt.PopupMenu;
import java.awt.event.MouseEvent;
import java.util.Vector;
public class AppletMenuBarDemo extends Applet {
public void init() {
AppletMenuBar menubar = new AppletMenuBar();
menubar.setForeground(Color.black);
menubar.setHighlightColor(Color.red);
menubar.setFont(new Font("helvetica", Font.BOLD, 12));
this.setLayout(new BorderLayout());
this.add(menubar, BorderLayout.NORTH);
PopupMenu file = new PopupMenu();
file.add("New...");
file.add("Open...");
file.add("Save As...");
PopupMenu edit = new PopupMenu();
edit.add("Cut");
edit.add("Copy");
edit.add("Paste");
menubar.addMenu("File", file);
menubar.addMenu("Edit", edit);
}
}
/*
* Copyright (c) 2000 David Flanagan. All rights reserved. This code is from the
* book Java Examples in a Nutshell, 2nd Edition. It is provided AS-IS, WITHOUT
* ANY WARRANTY either expressed or implied. You may study, use, and modify it
* for any non-commercial purpose. You may distribute it non-commercially as
* long as you retain this notice. For a commercial use license, or to purchase
* the book (recommended), visit http://www.davidflanagan.com/javaexamples2.
*/
class AppletMenuBar extends Panel {
// Menubar contents
Vector labels = new Vector();
Vector menus = new Vector();
// Properties
Insets margins = new Insets(3, 10, 3, 10); // top, left, bottom, right
int spacing = 10; // Space between menu labels
Color highlightColor; // Rollover color for labels
// internal stuff
boolean remeasure = true; // Whether the labels need to be remeasured
int[] widths; // The width of each label
int[] startPositions; // Where each label starts
int ascent, descent; // Font metrics
Dimension prefsize = new Dimension(); // How big do we want to be?
int highlightedItem = -1; // Which item is the mouse over?
/**
* Create a new component that simulates a menubar by displaying the
* specified labels. Whenever the user clicks the specified label, popup up
* the PopupMenu specified in the menus array. Elements of the menus arra
* may be a static PopupMenu object, or a PopupMenuFactory object for
* dynamically creating menus. Perhaps we'll also provide some other kind of
* constructor or factory method that reads popup menus out of a config
* file.
*/
public AppletMenuBar() {
// We'd like these kinds of events to be delivered
enableEvents(AWTEvent.MOUSE_EVENT_MASK
| AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
/** Add a popup menu to the menubar */
public void addMenu(String label, PopupMenu menu) {
insertMenu(label, menu, -1);
}
/** Insert a popup menu into the menubar */
public void insertMenu(String label, PopupMenu menu, int index) {
if (index < 0)
index += labels.size() + 1; // Position to put it at
this.add(menu); // Popup belongs to us
labels.insertElementAt(label, index); // Remember the label
menus.insertElementAt(menu, index); // Remember the menu
remeasure = true; // Remeasure everything
invalidate(); // Container must relayout
}
/** Property accessor methods for margins property */
public Insets getMargins() {
return (Insets) margins.clone();
}
public void setMargins(Insets margins) {
this.margins = margins;
remeasure = true;
invalidate();
}
/** Property accessor methods for spacing property */
public int getSpacing() {
return spacing;
}
public void setSpacing(int spacing) {
if (this.spacing != spacing) {
this.spacing = spacing;
remeasure = true;
invalidate();
}
}
/** Accessor methods for highlightColor property */
public Color getHighlightColor() {
if (highlightColor == null)
return getForeground();
else
return highlightColor;
}
public void setHighlightColor(Color c) {
if (highlightColor != c) {
highlightColor = c;
repaint();
}
}
/** We override the setFont() method so we can remeasure */
public void setFont(Font f) {
super.setFont(f);
remeasure = true;
invalidate();
}
/** Override these color property setter method so we can repaint */
public void setForeground(Color c) {
super.setForeground(c);
repaint();
}
public void setBackground(Color c) {
super.setBackground(c);
repaint();
}
/**
* This method is called to draw tell the component to redraw itself. If we
* were implementing a Swing component, we'd override paintComponent()
* instead
*/
public void paint(Graphics g) {
if (remeasure)
measure(); // Remeasure everything first, if needed
// Figure out Y coordinate to draw at
Dimension size = getSize();
int baseline = size.height - margins.bottom - descent;
// Set the font to draw with
g.setFont(getFont());
// Loop through the labels
int nummenus = labels.size();
for (int i = 0; i < nummenus; i++) {
// Set the drawing color. Highlight the current item
if ((i == highlightedItem) && (highlightColor != null))
g.setColor(getHighlightColor());
else
g.setColor(getForeground());
// Draw the menu label at the position computed in measure()
g.drawString((String) labels.elementAt(i), startPositions[i],
baseline);
}
// Now draw a groove at the bottom of the menubar.
Color bg = getBackground();
g.setColor(bg.darker());
g.drawLine(0, size.height - 2, size.width, size.height - 2);
g.setColor(bg.brighter());
g.drawLine(0, size.height - 1, size.width, size.height - 1);
}
/** Called when a mouse event happens over the menubar */
protected void processMouseEvent(MouseEvent e) {
int type = e.getID(); // What type of event?
int item = findItemAt(e.getX()); // Over which menu label?
if (type == MouseEvent.MOUSE_PRESSED) {
// If it was a mouse down event, then pop up the menu
if (item == -1)
return;
Dimension size = getSize();
PopupMenu pm = (PopupMenu) menus.elementAt(item);
if (pm != null)
pm.show(this, startPositions[item] - 3, size.height);
} else if (type == MouseEvent.MOUSE_EXITED) {
// If the mouse left the menubar, then unhighlight
if (highlightedItem != -1) {
highlightedItem = -1;
if (highlightColor != null)
repaint();
}
} else if ((type == MouseEvent.MOUSE_MOVED)
|| (type == MouseEvent.MOUSE_ENTERED)) {
// If the mouse moved, change the highlighted item, if necessary
if (item != highlightedItem) {
highlightedItem = item;
if (highlightColor != null)
repaint();
}
}
}
/** This method is called when the mouse moves */
protected void processMouseMotionEvent(MouseEvent e) {
processMouseEvent(e);
}
/** This utility method converts an X coordinate to a menu label index */
protected int findItemAt(int x) {
// This could be a more efficient search...
int nummenus = labels.size();
int halfspace = spacing / 2 - 1;
int i;
for (i = nummenus - 1; i >= 0; i--) {
if ((x >= startPositions[i] - halfspace)
&& (x <= startPositions[i] + widths[i] + halfspace))
break;
}
return i;
}
/**
* Measure the menu labels, and figure out their positions, so we can
* determine when a click happens, and so we can redraw efficiently.
*/
protected void measure() {
// Get information about the font
FontMetrics fm = this.getFontMetrics(getFont());
// Remember the basic font size
ascent = fm.getAscent();
descent = fm.getDescent();
// Create arrays to hold the measurements and positions
int nummenus = labels.size();
widths = new int[nummenus];
startPositions = new int[nummenus];
// Measure the label strings and
// figure out the starting position of each label
int pos = margins.left;
for (int i = 0; i < nummenus; i++) {
startPositions[i] = pos;
String label = (String) labels.elementAt(i);
widths[i] = fm.stringWidth(label);
pos += widths[i] + spacing;
}
// Compute our preferred size from this data
prefsize.width = pos - spacing + margins.right;
prefsize.height = ascent + descent + margins.top + margins.bottom;
// We've don't need to be remeasured anymore.
remeasure = false;
}
/**
* These methods tell the container how big the menubar wants to be.
*
*/
public Dimension getMinimumSize() {
return getPreferredSize();
}
public Dimension getPreferredSize() {
if (remeasure)
measure();
return prefsize;
}
/** @deprecated Here for compatibility with Java 1.0 */
public Dimension minimumSize() {
return getPreferredSize();
}
/** @deprecated Here for compatibility with Java 1.0 */
public Dimension preferredSize() {
return getPreferredSize();
}
/**
* This method is called when the underlying AWT component is created. We
* can't measure ourselves (no font metrics) until this is called.
*/
public void addNotify() {
super.addNotify();
measure();
}
/** This method tells the container not to give us keyboard focus */
public boolean isFocusTraversable() {
return false;
}
}
|