📄 xyplot.java
字号:
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.FontMetrics;
/**
* A class for simple x-y plots, showing up to 3 traces in a cartesian
* coordinate system.
*
* @version 1.0
* @author Hans U. Gerber (<a href="mailto:gerber@ifh.ee.ethz.ch">gerber@ifh.ee.ethz.ch</a>)
*/
public class XYPlot extends Plot {
RealPoint[][] trace;
Dimension previousSize = null;
public XYPlot() {
trace = new RealPoint[3][];
setWindow(0.0, -1.1, 1.05, 1.1);
}
void setViewport() {
Dimension d = size();
super.setViewport(4 + textWidth + 3 + 3, 4, d.width - 4, d.height - 4);
}
// private int counter = 0;
/**
* Updates one of 3 traces; the trace is immediately redrawn.
*/
public synchronized void setTrace(int which, RealPoint[] p) {
// I want to update a new trace as quickly and as smoothly as I can.
// I don't use double-buffering because it does not make sense to
// move whole bitmaps worth kilobytes when just a few pixels have to
// be updated.
// Requesting repaint() does not work with me because
// - it "calls update() as soon as possible" and several repaint
// requests may be merged into one
// - by calling update(), the background would be erased
// getGraphics() should work fine for this task but then I ran into
// a JDK AWT bug. It showed up with appletviewer and HotJava:
// I should be able to getGraphics() as many times as I want.
// But it seems to me that Windows resources (DCs?) are not properly
// freed. After a lot of calls, getGraphics() returns null.
// MS' jview and Explorer 3.0 ran fine, however.
// When I replaced MS' implementation of Win32Graphics.class in Sun's
// classes.zip, the problem went away. As a precaution, I now explicitely
// dispose() the graphics context.
// But then, this happened:
// When testing the applet with Sun's JDK java interpreter and
// appletviewer under Windows 95, the plot did not appear initially.
// I noticed that setTrace() caused paint() to be called when the
// size of the canvas was still [0,0]. Maybe the AWT then assumed that
// the canvas was already painted and did not repaint again.
// Now I have setTrace() call paint() only if the size is not zero:
//
Graphics g = getGraphics();
Dimension d = size();
boolean canPaint = (g != null && d.width != 0 && d.height != 0);
if (canPaint) {
// Erase the current image of the trace by painting it with
// the background color. This may cut holes into other traces
// and the axis. Therefore, I will repaint the whole plot after
// this:
setViewport();
drawTrace(g, trace[which], getBackground());
}
trace[which] = p;
if (canPaint) {
// Repaint all to fix any holes:
paint(g);
}
if (g != null) {
// As a quick fix for Sun's Windows resource leak bug,
// I explicitely free the graphics context:
g.dispose();
// (Before knew about dispose(), I used to do this:
// Collect garbage from time to time, hoping that
// Windows resources are freed as well:
//
// counter++;
// if (counter > 100) {
// System.gc();
// counter = 0;
// }
}
}
static final int FRAME_WIDTH = 4;
int textWidth = 0;
int textAscent = 0;
/**
* This method repaints the plot completely.
*/
public synchronized void paint(Graphics g) {
// After resizing a component, the AWT doesn't seem to call neither
// repaint() nor update(). It goes directly at paint().
// But I want a cleanly erased canvas after a resize, because not all
// of my drawing takes place in repaint().
// I force an update() (and therefore erasing the canvas)
// whenever paint() notices that the size of the canvas has changed:
//
Dimension d = size();
if (previousSize == null || previousSize.width != d.width || previousSize.height != d.height) {
previousSize = d;
update(g);
// This will erase the background and then call paint() recursively.
// Recursion stops as soon as changing the size stops.
}
if (textWidth == 0) {
FontMetrics metrics = g.getFontMetrics();
textWidth = metrics.stringWidth("+1");
textAscent = metrics.getAscent();
}
// Draw a 3-D frame:
Color bg = getBackground();
g.setColor(bg);
g.draw3DRect(0, 0, d.width - 1, d.height - 1, true);
g.draw3DRect(3, 3, d.width - 7, d.height - 7, false);
g.setColor(Color.black);
g.clipRect(4, 4, d.width - 8, d.height - 8);
setViewport();
g.setColor(Color.gray);
g.drawLine(xformX(xMin), xformY(0), xformX(xMax), xformY(0));
g.drawLine(xformX(0.0), xformY(yMax), xformX(0.0), xformY(yMin));
g.drawString("0", xformX(0.0)-textWidth, xformY(0.0)-1);
g.drawLine(xformX(1.0), xformY(0)-3, xformX(1.0), xformY(0.0)+3);
g.drawString(" 1", xformX(1.0)-textWidth/2, xformY(0.0)+3+textAscent);
g.drawLine(xformX(0.0)-3, xformY(1.0), xformX(0.0)+3, xformY(1.0));
g.drawString("+1", xformX(0.0)-3-textWidth-1, xformY(1.0)+textAscent/2);
g.drawLine(xformX(0.0)-3, xformY(-1.0), xformX(0.0)+3, xformY(-1.0));
g.drawString("-1", xformX(0.0)-3-textWidth-1, xformY(-1.0)+textAscent/2);
drawTrace(g, trace[0], new Color(255, 0, 0));
drawTrace(g, trace[1], new Color(0, 0, 0));
drawTrace(g, trace[2], new Color(0, 0, 255));
}
/**
* Draws one of the 3 traces.
*/
synchronized void drawTrace(Graphics g, RealPoint[] trace, Color color) {
if (trace != null) {
int nrOfPoints = trace.length;
int[] x = new int[nrOfPoints];
int[] y = new int[nrOfPoints];
for (int i = 0; i < nrOfPoints; i++) {
x[i] = xformX(trace[i].x);
y[i] = xformY(trace[i].y);
}
g.setColor(color);
// With older Java VMs, drawPolygon did not close the polygon.
// The newest VMs, however, do close it; and the documentation says so.
// This is dumb. A programmer can easily close a polyline, if he wants to.
// But there's no easy way to keep drawPolygon from closing the line.
// Do I really have to resort to a series of drawLines?
//
// g.drawPolygon(x, y, nrOfPoints);
for (int i = 0; i < nrOfPoints-1; i++) {
g.drawLine(x[i], y[i], x[i+1], y[i+1]);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -