So, I'm trying to dynamically draw a Polygon starting from when I click the mouse until I stop dragging and release. Instead of, for the purpose of this question, a square outline being drawn when I click, drag down, then right-across, then up, then left-across, this is what happens: http://imgur.com/t8ZN3Pp
Any suggestions?
Notes:
model.addPolygon() creates a Polygon with starting points and adds it to an ArrayList called 'polys'
model.addPolygonPoint() adds points to this created polygon that is stored in 'polys'
my paint function iterates through polys to paint
public void mousePressed(MouseEvent e) {
oldX = e.getX();
oldY = e.getY();
model.addPolygon(oldX, oldY);
}
public void mouseDragged(MouseEvent e) {
currentX = e.getX();
currentY = e.getY();
model.addPolyPoint(currentX, currentY);
repaint();
}
.
.
. then in paintComponent:
for (ListIterator<Polys> iter =
model.polys.listIterator(model.polys.size());
iter.hasPrevious();){
graphics2D.draw(iter.previous().poly);
Full paintComponent:
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (image == null) {
image = createImage(getSize().width, getSize().height);
graphics2D = (Graphics2D) image.getGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
}
g.drawImage(image, 0, 0, null);
for (ListIterator<Polys> iter =
model.polys.listIterator(model.polys.size());
iter.hasPrevious();){
graphics2D.draw(iter.previous().poly);
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
public class Testing {
private static int lastX;
private static int lastY;
private static int modX;
private static int modY;
private static final BasicStroke STROKE = new BasicStroke(2.0F);
private static final Point[] SHAPE = new Point[]{
new Point(10, 10),
new Point(10, 40),
new Point(60, 90),
new Point(50, 50)
};
public static void main(final String[] args) {
final JFrame frame = new JFrame("Polygon Movement");
final JPanel pane = new JPanel() {
@Override
public void paintComponent(final Graphics g1) {
final Graphics2D g = (Graphics2D) g1;
g.setColor(Color.RED);
g.translate(modX, modY);
g.setStroke(STROKE);
for (int i = 0; i < SHAPE.length; i++) {
g.drawLine(SHAPE[i].x, SHAPE[i].y, SHAPE[(i + 1) % SHAPE.length].x, SHAPE[(i + 1) % SHAPE.length].y);
}
}
};
pane.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
modX += e.getX() - lastX;
modY += e.getY() - lastY;
lastX = e.getX();
lastY = e.getY();
frame.repaint();
}
});
pane.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
lastX = e.getX();
lastY = e.getY();
}
});
pane.setPreferredSize(new Dimension(200, 200));
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
}
As you can see, I make a basic shape with defined points. It is the most effective way to do this, unless you wish to change the basic shape (here it is static). In that case, you find the point the mouse it 'grabbing' and modify that one. Either way, no adding or removing of points is needed. I use the terms lastX
instead of oldX
just by preference.
The BasicStroke is quite optional, same with casting to a Graphics2D
object.
The line:
g.drawLine(SHAPE[i].x, SHAPE[i].y, SHAPE[(i + 1) % SHAPE.length].x, SHAPE[(i + 1) % SHAPE.length].y);
Should make some sense if you've tried this thing before. It iterates through all the points, drawing a line from the current (SHAPE[i]
) to the next (SHAPE[(i + 1) & SHAPE.length
).
The reason behind that logic, is that say you have 4 points, as we do here. The last iteration through them, you will be given i = 3
. Due to this and the array only containing 4 indexes (0-3), we must get that value back down to zero. For simplicity I use the % SHAPE.length
so there wouldn't be a need for special cases.
I also opted to use adapters seeing as there were only 2 methods needed of the 7 possible ones.
If you have any questions feel free to ask me about this.
~Legend
If all you want to do is draw a polygon. You could simply use the Shape
API
This will allow you to "add" points to the shape and allow the shape to paint itself.
Here I use a simple Path2D
shape, as it allows me to append points over time. I keep a running list of shapes, which allows me to generate multiple polygons as required
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.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class DrawPolygon {
public static void main(String[] args) {
new DrawPolygon();
}
public DrawPolygon() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new PolyPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class PolyPane extends JPanel {
private MouseHandler mouseHandler;
private Path2D currentShape;
private List<Path2D> lstPloys;
private Point lastPoint;
private Point currentPoint;
public PolyPane() {
lstPloys = new ArrayList<>();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
@Override
public void addNotify() {
super.addNotify();
addMouseListener(getMouseHandler());
addMouseMotionListener(getMouseHandler());
}
@Override
public void removeNotify() {
removeMouseListener(getMouseHandler());
removeMouseMotionListener(getMouseHandler());
super.removeNotify();
}
public MouseHandler getMouseHandler() {
if (mouseHandler == null) {
mouseHandler = new MouseHandler();
}
return mouseHandler;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (lastPoint != null) {
g2d.setColor(Color.RED);
g2d.fillOval(lastPoint.x - 2, lastPoint.y - 2, 4, 4);
}
if (currentShape != null) {
g2d.setColor(Color.RED);
g2d.draw(currentShape);
if (lastPoint != null && currentPoint != null) {
System.out.println(lastPoint + " - " + currentPoint);
g2d.setColor(new Color(255, 0, 0, 64));
g2d.draw(new Line2D.Float(lastPoint, currentPoint));
}
}
g2d.setColor(Color.BLACK);
for (Shape shape : lstPloys) {
g2d.draw(shape);
}
g2d.dispose();
}
public class MouseHandler extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
if (e.getClickCount() == 1) {
Point p = e.getPoint();
lastPoint = p;
if (currentShape == null) {
currentShape = new Path2D.Float();
currentShape.moveTo(p.x, p.y);
} else {
currentShape.lineTo(p.x, p.y);
}
repaint();
} else if (e.getClickCount() == 2) {
currentShape.closePath();
lstPloys.add(currentShape);
currentShape = null;
lastPoint = null;
repaint();
}
}
}
@Override
public void mouseMoved(MouseEvent e) {
if (currentShape != null) {
currentPoint = e.getPoint();
repaint();
} else {
currentPoint = null;
}
}
}
}
}
Take a look at Working with Geometry for more details