This is a basic example that demonstrates the use of a Path2D
, to define a custom shape and an AffineTransformation
to transform the shape.
This example will cause the arrow to point towards the mouse as it moves over the panel
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateArrow {
public static void main(String[] args) {
new RotateArrow();
}
public RotateArrow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new RotatePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RotatePane extends javax.swing.JPanel {
private Point mousePoint;
private PointyThing pointyThing;
public RotatePane() {
pointyThing = new PointyThing();
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
mousePoint = e.getPoint();
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mousePoint != null) {
int x = width / 2;
int y = height / 2;
int deltaX = mousePoint.x - x;
int deltaY = mousePoint.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
Rectangle bounds = pointyThing.getBounds();
AffineTransform at = new AffineTransform();
at.translate((width - bounds.width) / 2, (height - bounds.height) / 2);
at.rotate(Math.toRadians(rotation), bounds.width / 2, bounds.height / 2);
Shape shape = new Path2D.Float(pointyThing, at);
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.fill(shape);
g2d.draw(shape);
g2d.dispose();
}
}
public class PointyThing extends Path2D.Float {
public PointyThing() {
moveTo(15, 0);
lineTo(30, 15);
lineTo(0, 15);
lineTo(15, 0);
moveTo(15, 15);
lineTo(15, 60);
}
}
}
Update with example two
Basically, this uses the PointyThing
as the arrow head only, and draws the line separately.
The arrow is orientated so it will point down the line (towards the mouse)
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class RotateArrow {
public static void main(String[] args) {
new RotateArrow();
}
public RotateArrow() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new RotatePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RotatePane extends javax.swing.JPanel {
private PointyThing pointyThing;
private Point mouseStart;
private Point mouseEnd;
public RotatePane() {
pointyThing = new PointyThing();
MouseAdapter ma = new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
mouseEnd = e.getPoint();
repaint();
}
@Override
public void mouseClicked(MouseEvent e) {
mouseStart = e.getPoint();
repaint();
}
};
addMouseListener(ma);
addMouseMotionListener(ma);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (mouseStart != null && mouseEnd != null) {
double rotation = 0f;
int width = getWidth() - 1;
int height = getHeight() - 1;
if (mouseEnd != null) {
int x = mouseStart.x;
int y = mouseStart.y;
int deltaX = mouseEnd.x - x;
int deltaY = mouseEnd.y - y;
rotation = -Math.atan2(deltaX, deltaY);
rotation = Math.toDegrees(rotation) + 180;
}
Rectangle bounds = pointyThing.getBounds();
g2d.setStroke(new BasicStroke(3));
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Float(mouseStart, mouseEnd));
AffineTransform at = new AffineTransform();
at.translate(mouseEnd.x - (bounds.width / 2), mouseEnd.y - (bounds.height / 2));
at.rotate(Math.toRadians(rotation), bounds.width / 2, bounds.height / 2);
Shape shape = new Path2D.Float(pointyThing, at);
g2d.fill(shape);
g2d.draw(shape);
}
g2d.dispose();
}
}
public class PointyThing extends Path2D.Float {
public PointyThing() {
moveTo(15, 0);
lineTo(30, 15);
lineTo(0, 15);
lineTo(15, 0);
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…