📄 arrowcomponent.java
字号:
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package eti.bi.alphaminer.operation.operator;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
import eti.bi.alphaminer.operation.operator.Operator;
/**
* ArrowComponent is a component with rectangular bound which
* has an "arrow drawing" in diagonal/vertical/horizontal manner.
*/
public class ArrowComponent extends JComponent {
/**
*
*/
private static final long serialVersionUID = 7029789805581376935L;
/* eight possible directions of an arrow */
protected static final int NORTH = 0;
protected static final int NORTHEAST = 1;
protected static final int EAST = 2;
protected static final int SOUTHEAST = 3;
protected static final int SOUTH = 4;
protected static final int SOUTHWEST = 5;
protected static final int WEST = 6;
protected static final int NORTHWEST = 7;
/* the color of the arrow */
protected Color color;
/* the direction where the arrow is pointing to (i.e. NORTH/NORTHEAST/EAST..... etc.) */
protected int target;
/* the two components that is related to this arrow component */
protected JComponent from, to;
protected int fromX, fromY, toX, toY;
/* storing the appropriate length of the "arrow drawing" after computations */
protected int arrowLength;
/* the final product of the arrow drawing after matrix multiplications */
protected Shape arrow;
/* record the old related components bounds for skip unnecessary drawings */
Rectangle oldFrom, oldTo;
private boolean tempDrawState = true;
public static int clickableDistance = 12;
/**
* Constrcts an ArrowComponent.
* @param from JComponent that the ArrowComponent is pointing out.
* @param to JComponent that the ArrowComponent is pointing to.
* @param state the drawing state. True if it is a permanent ArrowComponent;
* false if it is a temporary ArrowComponent.
*/
public ArrowComponent(JComponent from, JComponent to, boolean state) {
super();
this.tempDrawState = state;
this.from = from;
this.to = to;
color = Color.black;
/* after getting the two related components, immediately
compute the arrow and the bounds of this ArrowComponent. */
refreshPath();
}
/**
* Gets the parent node.
* @return JComponent the parent node.
*/
public JComponent getParentNode() {
return from;
}
/**
* Gets the child node.
* @return JComponent the child node.
*/
public JComponent getChildNode() {
return to;
}
/**
* Refreshes path of the ArrowComponent drawn.
*/
public void refreshPath() {
/* get the two end points of the arrow bound.
(i.e. the centers of the two related component) */
Rectangle f = null;
Rectangle t = null;
/* IF the compenont is an Operaotr object, get the Icon Bounds
* instead of the component bounds*/
if (from instanceof Operator)
{
f = ((Operator)from).getIconBounds();
}else
{
f = from.getBounds();
}
if (to instanceof Operator)
{
t = ((Operator)to).getIconBounds();
}else
{
t = to.getBounds();
}
if (tempDrawState) {
fromX = f.x + f.width / 2;
toX = t.x + t.width / 2;
fromY = f.y + f.height / 2;
toY = t.y + t.height / 2;
} else {
fromX = f.x + f.width / 2;
fromY = f.y + 17;
if ((f.x + 49) <= (t.x + 17)) {
toX = t.x;
toY = t.y + 17;
} else if ((f.x + 17) >= (t.x + 49)) {
toX = t.x + t.width;
toY = t.y + 17;
} else if (f.y >= t.y) {
toX = t.x + t.width / 2;
toY = t.y + t.height;
} else {
toX = t.x + t.width / 2;
toY = t.y + 2;
}
}
/* if no position change on related components, do nothing. */
if (oldFrom != null
&& oldTo != null
&& oldFrom.equals(f)
&& oldTo.equals(t)) {
return;
}
/* record the new bounds */
oldFrom = f;
oldTo = t;
/* the arrow should be in horizontal direction */
if (fromY == toY) {
/* west */
if (fromX > toX) {
target = WEST;
setBounds(toX, toY - 10, fromX - toX + 1, 21);
arrowLength = fromX - toX + 1;
}
/* east */
else if (fromX < toX) {
target = EAST;
setBounds(fromX, fromY - 10, toX - fromX + 1, 21);
arrowLength = toX - fromX + 1;
}
/* zero size, since "from" point is equal to "to" point. */
else {
setBounds(fromX, fromY, 0, 0);
arrowLength = 0;
}
}
/* the arrow should be in vertical direction */
else if (fromX == toX) {
/* north */
if (fromY > toY) {
target = NORTH;
setBounds(toX - 10, toY, 21, fromY - toY + 1);
arrowLength = fromY - toY + 1;
}
/* south */
else {
target = SOUTH;
setBounds(fromX - 10, fromY, 21, toY - fromY + 1);
arrowLength = toY - fromY + 1;
}
}
/* the arrow should be in diagonal direction */
else {
if (fromX < toX && fromY < toY) {
target = SOUTHEAST;
} else if (fromX < toX && fromY > toY) {
target = NORTHEAST;
} else if (fromX > toX && fromY > toY) {
target = NORTHWEST;
} else if (fromX > toX && fromY < toY) {
target = SOUTHWEST;
}
int width = Math.abs(fromX - toX) + 1;
int height = Math.abs(fromY - toY) + 1;
setBounds(
Math.min(fromX, toX),
Math.min(fromY, toY),
width,
height);
arrowLength = (int) Math.sqrt(width * width + height * height);
}
/* the original arrowLength after the computation should be the same as the distance
between two endpoints, now it is shortened for better display outlook. (Since it is
more desirable that it don't block too much of the "rectangle drawings". */
//arrowLength-=30;
/* compute the arrow shape with matrix rotation and translation... etc. */
arrow = computeArrow();
/* the original bounds should be set as the two end points of the related components.
now it is made to grow larger because sometimes the arrow drawing is chopped off
if the bound is too tight. */
Rectangle oldbound = getBounds();
setBounds(
oldbound.x - 30,
oldbound.y - 30,
oldbound.width + 60,
oldbound.height + 60);
}
/**
* De-select the current ArrowComponent.
*/
public void clearSelect() {
color = Color.black;
repaint();
}
/**
* Selects the current ArrowComponent.
*/
public void setSelect() {
color = Color.blue;
repaint();
}
/**
* @see javax.swing.JComponent#paintComponent(Graphics)
*/
public void paintComponent(Graphics g) {
super.paintComponent(g);
// recompute the arrow shape
refreshPath();
if (arrow != null) {
g.setColor(color);
// draw the arrow in the graphic object.
// since the buffer was made to be grown larger than the original one,
// therefore the shape is needed to be translated by the offset
// (Note that the original bounds, X and Y have been both minus by 30 units, so
// now the arrow drawing is moved by 30 units to cover the loss.)
// here Graphics2D is used because drawing "Shape" object on the Graphics class
// is not directly supported.
// Note that type-casting here potentially may generate problems,
// however it works for this JDK 1.2.2
((Graphics2D) g).fill(
AffineTransform.getTranslateInstance(
30,
30).createTransformedShape(
arrow));
}
}
/**
* @see java.awt.Component#contains(int, int)
*/
public boolean contains(int x, int y) {
Line2D lineBetweenEndPoints = new Line2D.Double();
lineBetweenEndPoints.setLine(fromX, fromY, toX, toY);
if (lineBetweenEndPoints.ptSegDist(x, y) <= clickableDistance)
return true;
else
return false;
}
/**
* Computes shape of the ArrowComponent.
* @return Shape the shape (which is a polygon) of the ArrowComponent.
*/
private Shape computeArrow() {
/* read the bound of the computation area */
Rectangle bounds = getBounds();
/* get the center position of the draw area
so simply first draw an arrow pointing East,
then rotate it about the center to appropriate direction. */
int centerX = bounds.width / 2;
int centerY = bounds.height / 2;
/* make an arrow shape pointing to east first */
Polygon result = new Polygon();
result.addPoint(centerX - arrowLength / 2, centerY - 1);
result.addPoint(centerX + arrowLength / 2 - 8, centerY - 1);
result.addPoint(centerX + arrowLength / 2 - 8, centerY - 4);
result.addPoint(centerX + arrowLength / 2, centerY);
result.addPoint(centerX + arrowLength / 2 - 8, centerY + 4);
result.addPoint(centerX + arrowLength / 2 - 8, centerY + 1);
result.addPoint(centerX - arrowLength / 2, centerY + 1);
/* close the polygon */
result.addPoint(centerX - arrowLength / 2, centerY - 3);
/* if our arrow should pointing the East, otherwise do nothing. */
if (target == EAST) {
return result;
}
/* if pointing West, we rotate it by 180 degrees. */
else if (target == WEST) {
return AffineTransform
.getRotateInstance(Math.PI, centerX, centerY)
.createTransformedShape(result);
}
/* if pointing South, we rotate it by 90 degrees. */
else if (target == SOUTH) {
return AffineTransform
.getRotateInstance(Math.PI / 2, centerX, centerY)
.createTransformedShape(result);
}
/* if pointing North, we rotate it by 270 degrees. */
else if (target == NORTH) {
return AffineTransform
.getRotateInstance(Math.PI * 1.5, centerX, centerY)
.createTransformedShape(result);
}
/* for the other four direction,
we rotate it by computing the arc tangent appropriately. */
else if (target == SOUTHEAST) {
return AffineTransform
.getRotateInstance(
Math.atan(((double) bounds.height) / bounds.width),
centerX,
centerY)
.createTransformedShape(result);
} else if (target == SOUTHWEST) {
return AffineTransform
.getRotateInstance(
Math.atan(((double) bounds.width) / bounds.height)
+ Math.PI / 2,
centerX,
centerY)
.createTransformedShape(result);
} else if (target == NORTHWEST) {
return AffineTransform
.getRotateInstance(
Math.atan(((double) bounds.height) / bounds.width)
+ Math.PI,
centerX,
centerY)
.createTransformedShape(result);
} else {
return AffineTransform
.getRotateInstance(
Math.atan(((double) bounds.width) / bounds.height)
+ Math.PI * 1.5,
centerX,
centerY)
.createTransformedShape(result);
}
}
public void dispose() {
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -