Grinding3.java
Appearance
Back to Grinding Java - Enhancing the AWT
package GUITools; import java.AWT.*; import java.AWT.event.*; import java.util.Vector; /** * The Tooltip class was developed for use by the DockableToolbar class, * I chose to make it public since i feel that with slight modification * it can be used in other classes. * This class doesnt have a simple API (mostly because it was developed * for internal use), it has a more generic wrapper (class Hints) which I reccomend on using. * This class draws a yellow label tooltip (or hint/hovering help...). * The Tooltip class only displays a tooltip at a given X,Y location in * A container, if that container has Components in it that hide the tooltip * it will try to display on them too. The mouse functionality and the full * capabilities of a Tooltip are not implemented here, I will probably subclass * this class in a later stage to create an automatic Tooltip facility. * This class was developed to run under JDK 1.1.1, with very little assistance * from VisualAge for Java, most of the work was done using javac. * This class was written by Shai Almog 5/4/97. The sorce is in the public * domain and may be modified and used freely. It is not a requirment but * I would consider it good manners if you credit me and EDM/2 (www.edm2.com) * in applications in which this code was used ;-) **/ public class Tooltip extends Canvas // The reason we extend Canvas and not Component // is due to a bug in VisualAge for Java which did not allow this. { /** * The Tooltip constructor takes the following parameters * caption - the text of the tooltip. * tooltipFont - the font of the tooltip. * c - The Container on which the Tooltip will be displayed. * x - The x axis on which the Tooltip will be placed. Relative to the container. * y - The y asis on which the Tooltip will be placed. Relative to the container. */ public Tooltip(String caption,Font tooltipFont,Container c,int x, int y) { super(); // Calling the parent class constructor. containerOnWhichTheTooltipShows = c; containerOnWhichTheTooltipShows.add(this); // Adding ourselves as a component // of the container. this.tooltipFont = tooltipFont; this.caption = caption; FontMetrics fontSize = getToolkit().getFontMetrics(tooltipFont); // Checking the // size of the font. width = fontSize.stringWidth(caption); // Computing the size of the box in which // the string height = fontSize.getHeight(); // should be shown. if (x < 0) x = 0; // Checking the validity of the x and y parameters. if (y < 0) y = 0; // This should be the job of the class displaying the Tooltip, if (x + width > containerOnWhichTheTooltipShows.getSize().width) // but we want // robust code! x = containerOnWhichTheTooltipShows.getSize().width - width; if (y + height > containerOnWhichTheTooltipShows.getSize().height) y = containerOnWhichTheTooltipShows.getSize().height - height; this.x = x; this.y = y; } /** * The dispose method removes the remains of the tooltip from the Container * This method must be called to remove the Tooltip! */ public void dispose() { containerOnWhichTheTooltipShows.remove(this); // Removing the tooltip // Component from the container. if(listOfComponentsToDrawOn != null) // If we drew on any Components // other than the Container. for (int counterOfComponentsToDrawOn = 0; counterOfComponentsToDrawOn < listOfComponentsToDrawOn.length; counterOfComponentsToDrawOn++) { if ((listOfComponentsToDrawOn[counterOfComponentsToDrawOn] instanceof Button) && (!(listOfComponentsToDrawOn[counterOfComponentsToDrawOn] instanceof ImageButton))) { // This is a patch to prevent buttons from disappearing when you repaint them. // For some reason in windows JDK when I call repaint on a Button it vanishes. Button b = (Button) listOfComponentsToDrawOn[counterOfComponentsToDrawOn]; b.setLabel(b.getLabel()); } else { listOfComponentsToDrawOn[counterOfComponentsToDrawOn].repaint(); listOfComponentsToDrawOn[counterOfComponentsToDrawOn].validate(); } } } public int getHeight() // This method returns the height of the Tooltip. { return (height); } public int getWidth() // This method returns the width of the Tooltip. { return (width); } public int getX() // Returns the x asis of the tooltip. { return (x); } public int getY() // Returns the y asis of the tooltip. { return (y); } /** * This method draws the Tooltip on the Container and then seeks all of the * components that overlap the Tooltip in the Container and it draws * the parts that were cliped by that Component on every sub Component. **/ public void paint(Graphics g) { // The paint is called with a clipped graphics. we draw but // clipping will probably occure so we must fix it. // We don't fix clipping at the end of the Container! That // is the applications responsibility. g.setColor(Color.black); g.fillRect(x, y, width + 2,height + 2); g.setColor(Color.yellow); g.fillRect(x + 1,y + 1,width,height); g.setColor(Color.black); g.setFont(tooltipFont); g.drawString(caption,x + 1,y + height - 1); if (containerOnWhichTheTooltipShows.getComponentCount() != 0) { // if there are any components, check for cliping. if(listOfComponentsToDrawOn == null) listOfComponentsToDrawOn = getComponentsAt(x, y, width + 2,height + 2); if(listOfComponentsToDrawOn != null) for (int componentIterator = 0; componentIterator < listOfComponentsToDrawOn.length; componentIterator++) drawLabelOnComponent(listOfComponentsToDrawOn[componentIterator], new Point(x, y), new Point(x + width + 2,y + height + 2)); } } /** * This method draws the fragment of the tooltip that shows on the Component * on too a Component. It gets absolute postions relative to the Container and * computes the points relative to the Container. */ private void drawLabelOnComponent(Component c, Point topLeft, Point bottomRight) { // This method computes the X and Y relative to the // Component and not the Container. computeAbsolutePointsInComponents(c.getLocation(),topLeft, bottomRight); Graphics g = c.getGraphics(); if(g != null) { g.setColor(Color.black); g.fillRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x - 2, bottomRight.y - topLeft.y - 2); g.setColor(Color.yellow); g.fillRect(topLeft.x + 1,topLeft.y + 1,bottomRight.x - 3 - topLeft.x, bottomRight.y - 3 - topLeft.y); g.setColor(Color.black); g.setFont(tooltipFont); g.drawString(caption,topLeft.x + 1,bottomRight.y - 3); } } /** * The getComponentsAt method is called by paint and returns an array of * Components that are overlapping the boundries given to it. * This is used to determine on which of the Components the Tooltip should be * drawn. */ private Component[] getComponentsAt(int x, int y, int width, int height) { Component[] listOfComponents = containerOnWhichTheTooltipShows.getComponents(); // Getting all of the Components in the Container. int componentCounter = listOfComponents.length; for (int componentIterator = 0 ; componentIterator < listOfComponents.length ; componentIterator++) { // Filtering out the Components that don't overlap. if (!isClipping(listOfComponents[componentIterator],new Point(x,y), new Point(width + x,height + y))) { listOfComponents[componentIterator] = null; componentCounter--; } } if(componentCounter > 0) // If any Component overlaps... { Component[] returnValue = new Component[componentCounter]; // Allocate space for the overlaping Components. int componentIterator = 0, secondaryComponentIterator = 0; for (; componentIterator < listOfComponents.length ; componentIterator++) if(listOfComponents[componentIterator] != null) { // Create a new filterd list of Components. returnValue[secondaryComponentIterator] = listOfComponents[componentIterator]; secondaryComponentIterator++; } return(returnValue); } else return(null); } /** * The isClipping method is used by the getComponentsAt method to determine if * 2 Components overlap each other. * This method returns true if the component will clip the location to bottom * rectangle. **/ private boolean isClipping(Component c,Point location,Point bottom) { Point cLocation = c.getLocation(), cBottom = new Point(cLocation.x + c.getSize().width, c.getSize().height + cLocation.y), topRight = new Point(bottom.x,location.y), bottomLeft = new Point(location.x,bottom.y); return(isPointInTheMiddle(location,cLocation,cBottom) || isPointInTheMiddle(bottom,cLocation,cBottom) || isPointInTheMiddle(topRight,cLocation,cBottom) || isPointInTheMiddle(bottomLeft,cLocation,cBottom)); } /** * This method is used by the isClipping method to determine if the point * p is in the rectangle between points top and bottom. **/ private static boolean isPointInTheMiddle(Point p,Point top,Point bottom) { return(((p.x >= top.x) && (p.x <= bottom.x) && (p.y >= top.y) && (p.y <= bottom.y))); } /** * The computeAbsolutePointsInComponents method is used by the * drawLabelOnComponent method to convert the Container based point to * Component asis points. **/ private void computeAbsolutePointsInComponents(Point origin, Point topLeft, Point bottomRight) { topLeft.x = topLeft.x - origin.x; bottomRight.x = bottomRight.x - origin.x; topLeft.y = topLeft.y - origin.y; bottomRight.y = bottomRight.y - origin.y; } public static int MINIMUM_SPACE_FOR_TOOLTIP = 50; // These are some // constants to help place public static int LEFT_SPACE_FOR_TOOLTIP = 100; // Tooltips in the // Correct position. public static int RIGHT_SPACE_FOR_TOOLTIP = 10; private Component[] listOfComponentsToDrawOn; // This is the list of Components // we are drawing on. private Container containerOnWhichTheTooltipShows;// The container on which the // Tooltip shows. private String caption; // The text of the Tooltip. private int x; // The tooltips x asis. private int y; // The tooltips y asis. private Font tooltipFont; // The tooltips Font. private int width; // The tooltips width. private int height; // The tooltips height. }