最近碰到的给预览图加测量工具,测量图之间点与点的距离。最后实现的效果如下:
添加的方法如下:
首先新建一个测量工具的类(基本类):
public class MeasuringLine {
Point2D startPoint;//第一个点
Point2D endPoint;
Point2D MiddlePoint; // 拖拽过程中的点,可以显示拖拽的痕迹
String strdistance;
double scale = 1;
private BasicStroke lineStroke = new BasicStroke(1.0f);;
public String getStrdistance() {
return strdistance;
}
public MeasuringLine(Point2D startPos, Point2D endPos, double d) {
startPoint = startPos;
endPoint = endPos;
this.scale = d;
MeasuringDistance();
}
public MeasuringLine(Point2D startPos, double scale) {
startPoint = startPos;
this.scale = scale;
}
public void MeasuringDistance() {
double x, y;
x = startPoint.getX() / scale; // 页面可以缩放,这个时候需要计算真实的坐标
y = startPoint.getY() / scale;
startPoint = new Point2D.Double(x, y);
x = endPoint.getX() / scale;
y = endPoint.getY() / scale;
endPoint = new Point2D.Double(x, y);
x = (startPoint.getX() + endPoint.getX()) / 2;
y = (int) ((startPoint.getY() + endPoint.getY()) / 2);
MiddlePoint = new Point2D.Double(x, y);
double distance = Point2D.distance(startPoint.getX(),
startPoint.getY(), endPoint.getX(), endPoint.getY());
int unitType = SystemParam.getInstance().getUnitType();
distance = (float) Unit.parseToDisplayData2(unitType,
String.valueOf(distance)); // 一般鼠标获取的点都是磅值,需要进行转换,这里换成mm值
DecimalFormat decimalFormat = new DecimalFormat(".00");// 构造方法的字符格式这里如果小数不足2位,会以0补足.
String p = decimalFormat.format(distance);
strdistance = p + "mm";
}
public Point2D getStartPoint() {
return startPoint;
}
public Point2D getEndPoint() {
return endPoint;
}
public Point2D getMiddlePoint() {
return MiddlePoint;
}
// 绘制图像
public void paint(Graphics2D g2d, double x1, double y1, double x2, double y2) {
Line2D.Double line2D = null;
Arrow.Attributes arrowAttributes = null;
line2D = new Line2D.Double(x1, y1, x2, y2);
arrowAttributes = new Arrow.Attributes(); // 绘制的箭头
arrowAttributes.angle = 30;
arrowAttributes.height = 10;
drawLineArrowDirectionAll(g2d, arrowAttributes, line2D);
}
private void drawLineArrowDirectionAll(Graphics2D g2d,
Arrow.Attributes arrowAttributes, Line2D.Double line2D) {
drawLine(g2d, line2D);
drawArrow(g2d, arrowAttributes, line2D.getP1(), line2D.getP2());
drawArrow(g2d, arrowAttributes, line2D.getP2(), line2D.getP1());
}
private void drawLine(Graphics2D g2d, Line2D.Double line2D) {
g2d.setColor(Color.red);
g2d.setStroke(lineStroke);
g2d.draw(line2D);
}
private void drawArrow(Graphics2D g2d, Arrow.Attributes arrowAttributes,
Point2D point1, Point2D point2) {
// 获取Arrow实例
Arrow arrow = getArrow(arrowAttributes, point1, point2);
// 构建GeneralPath
GeneralPath arrow2D = new GeneralPath();
arrow2D.moveTo(arrow.point1.x, arrow.point1.y);
arrow2D.lineTo(arrow.point2.x, arrow.point2.y);
arrow2D.lineTo(arrow.point3.x, arrow.point3.y);
arrow2D.closePath();
// 绘制
g2d.setColor(arrow.attributes.color);
g2d.fill(arrow2D);
}
private Arrow getArrow(Arrow.Attributes arrowAttributes, Point2D point1,
Point2D point2) {
Arrow arrow = new Arrow(arrowAttributes);
// 计算斜边
double hypotenuse = arrow.attributes.height
/ Math.cos(Math.toRadians(arrow.attributes.angle / 2));
// 计算当前线所在的象限
int quadrant = -1;
if (point1.getX() > point2.getX() && point1.getY() < point2.getY()) { // 判断测量的点是否超过了页面的尺寸
quadrant = 1;
} else if (point1.getX() < point2.getX()
&& point1.getY() < point2.getY()) {
quadrant = 2;
} else if (point1.getX() < point2.getX()
&& point1.getY() > point2.getY()) {
quadrant = 3;
} else if (point1.getX() > point2.getX()
&& point1.getY() > point2.getY()) {
quadrant = 4;
}
// 计算线的夹角
double linAngle = getLineAngle(point1.getX(), point1.getY(),
point2.getX(), point2.getY());
if (Double.isNaN(linAngle)) {
// 线与x轴垂直
if (point1.getX() == point2.getX()) {
if (point1.getY() < point2.getY()) {
linAngle = 90;
} else {
linAngle = 270;
}
quadrant = 2;
}
}
// 线与y轴垂直
else if (linAngle == 0) {
if (point1.getY() == point2.getY()) {
if (point1.getX() < point2.getX()) {
linAngle = 0;
} else {
linAngle = 180;
}
quadrant = 2;
}
}
// 上侧一半箭头
double xAngle = linAngle - arrow.attributes.angle / 2; // 与x轴夹角
double py0 = hypotenuse * Math.sin(Math.toRadians(xAngle)); // 计算y方向增量
double px0 = hypotenuse * Math.cos(Math.toRadians(xAngle)); // 计算x方向增量
// 下侧一半箭头
double yAngle = 90 - linAngle - arrow.attributes.angle / 2; // 与y轴夹角
double px1 = hypotenuse * Math.sin(Math.toRadians(yAngle));
double py1 = hypotenuse * Math.cos(Math.toRadians(yAngle));
// 第一象限
if (quadrant == 1) {
px0 = -px0;
px1 = -px1;
} else if (quadrant == 2) {
// do nothing
} else if (quadrant == 3) {
py0 = -py0;
py1 = -py1;
} else if (quadrant == 4) {
py0 = -py0;
px0 = -px0;
px1 = -px1;
py1 = -py1;
}
// build
arrow.point1 = new Point2D.Double();
arrow.point1.x = point1.getX();
arrow.point1.y = point1.getY();
arrow.point2 = new Point2D.Double();
arrow.point2.x = point1.getX() + px0;
arrow.point2.y = point1.getY() + py0;
arrow.point3 = new Point2D.Double();
arrow.point3.x = point1.getX() + px1;
arrow.point3.y = point1.getY() + py1;
return arrow;
}
protected double getLineAngle(double x1, double y1, double x2, double y2) {
double k1 = (y2 - y1) / (x2 - x1);
double k2 = 0;
return Math.abs(Math.toDegrees(Math.atan((k2 - k1) / (1 + k1 * k2))));
}
public static class Arrow {
Attributes attributes;
Point2D.Double point1;
Point2D.Double point2;
Point2D.Double point3;
public Arrow(Attributes attributes) {
this.attributes = attributes;
}
public static class Attributes {
double height; // 箭头的高度
double angle; // 箭头角度
Color color; // 箭头颜色
public Attributes() {
this.height = 20;
this.angle = 30;
this.color = Color.RED;
}
}
}
}
2. 添加鼠标监听的类:
public class MeasuringTool implements MouseListener {
int flag; // flag=1代表Mouse Moved,flag=2代表Mouse Dragged
int x = 0;
int y = 0;
double startx;
double starty;
double endx;// 起始坐标与终点坐标
double endy;
MeasuringLine Currentline;
ImagePane mainPanel; // 呈现的那个面板,最终我们是要把箭头画在这个页面上
Graphics g;
boolean selectLine = false;
/** 处理鼠标拖动的事件处理器 */
private MouseInputListener dragHandler = new DragHandler();
public MeasuringTool(ImagePane imagePanel) {
mainPanel = imagePanel;
mainPanel.addMouseListener(this);
mainPanel.addMouseMotionListener(dragHandler);
}
@Override
/* 由mousePressed(),mouseReleased()取得鼠标拖曳的开始与结束坐标 */
public void mousePressed(MouseEvent e) {
Point2D pos = mainPanel.getMousePosition();
startx = pos.getX();
starty = pos.getY();
if (startx > mainPanel.getImageWidth()
|| starty > mainPanel.getImageHeight()) {
return;
} else {
Currentline = new MeasuringLine(pos, mainPanel.getScale());
}
}
@Override
public void mouseReleased(MouseEvent e) {
if (Currentline != null) {
Point2D pos = mainPanel.getMousePosition();
if (pos == null)
return;
endx = pos.getX();
endy = pos.getY();
if (endx > mainPanel.getImageWidth())
endx = mainPanel.getImageWidth();
if (endy > mainPanel.getImageHeight())
endy = mainPanel.getImageHeight();
Currentline.endPoint = new Point2D.Double(endx, endy);
// mainPanel.addMeasuringLine(line1);
mainPanel.repaint();
Currentline = null;
}
}
public void mouseDragged(MouseEvent e) {
Point2D pos = mainPanel.getMousePosition();
double x = pos.getX();
double y = pos.getY();
if (x > mainPanel.getImageWidth())
x = mainPanel.getImageWidth();
if (y > mainPanel.getImageHeight())
y = mainPanel.getImageHeight();
Currentline.endPoint = new Point2D.Double(x, y);
mainPanel.addMeasuringLine(Currentline);
mainPanel.repaint();
}
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
/** 处理鼠标拖动的事件处理器 */
private class DragHandler extends MouseInputAdapter {
private int anchorX, anchorY;
@Override
public void mouseDragged(MouseEvent e) {
Point2D pos = mainPanel.getMousePosition();
if (pos == null)
return;
else {
double x = pos.getX();
double y = pos.getY();
if (x > mainPanel.getImageWidth())
x = mainPanel.getImageWidth();
if (y > mainPanel.getImageHeight())
y = mainPanel.getImageHeight();
Currentline.endPoint = new Point2D.Double(x, y);
mainPanel.addMeasuringLine(Currentline);
mainPanel.repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {
}
}
}
3. 最后显示的地方:
public class ImagePane extends JLayeredPane implements Scrollable,
Zoomable {
private List<MeasuringLine> measuringLine = new ArrayList<MeasuringLine>();
public ImagePane (float maxZoomScale, float minZoomScale) {
this(maxZoomScale, minZoomScale, true);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, (int) (image.getWidth() * scale),
(int) (image.getHeight() * scale), this);
Color oldColor = g.getColor();
// 画矩形边框
g.setColor(Color.BLACK);
g.drawRect(0, 0, (int) (image.getWidth() * scale),
(int) (image.getHeight() * scale));
g.setColor(oldColor);
// 这个地方就是添加画箭头的地方
Graphics2D g2 = (Graphics2D) g.create();
Color beforeColor = g.getColor();
g.setColor(Color.red);
for (int i = 0; i < measuringLine.size(); i++) {
MeasuringLine line1 = measuringLine.get(i);
line1.MeasuringDistance();
// 绘制线的“双向”箭头
double startx = line1.getStartPoint().getX() * scale;
double starty = line1.getStartPoint().getY() * scale;
double endX = line1.getEndPoint().getX() * scale;
double endY = line1.getEndPoint().getY() * scale;
double Middlex = line1.getMiddlePoint().getX() * scale;
double Middley = line1.getMiddlePoint().getY() * scale;
line1.paint(g2, startx, starty, endX, endY);
g.drawString(line1.getStrdistance(), (int) Middlex,
(int) Middley);
}
g.setColor(beforeColor);
}
this.setPreferredSize(new Dimension(
(int) (image.getWidth() * scale),
(int) (image.getHeight() * scale)));
this.updateUI();
}
}
这样就可以实现页面的测距功能。