问题
I'm trying to draw lines with Java Swing. The goal is to open an image inside the panel and draw lines on that image. When I try to draw a single line and drag the mouse, I get this behavior:
My code:
// Somewhere in the code:
imgLabel= new JLabel(new ImageIcon(buffImage)); // buffImage is a BufferedImage
...
Point point1;
Point point2;
Line2D line2d;
public void draw() {
Graphics2D g1 = this.buffImage.createGraphics();
g1.setRenderingHint(enderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g1.setColor(Color.RED);
g1.setStroke(new BasicStroke(1.5f));
if (point1 != null && point2 != null) {
g1.draw(line2d);
this.imgLabel.repaint();
}
}
class ImageMouseListener extends MouseAdapter {
@Override
public void mousePressed(MouseEvent me) {
point1 = me.getPoint();
}
@Override
public void mouseDragged(MouseEvent me) {
point2 = me.getPoint();
line2d = new Line2D.Double(point1, point2);
draw();
}
}
回答1:
The code you provide for drawing is correct. The issue here is that whenever you move your mouse cursor, the program is going to draw another line from the starting point to your current mouse position, resulting in the effect you show us (you're just forgetting to delete the old line).
To fix this, every time the mouse is moved you need to:
- Draw the previous line again using XOR mode
- Draw the second line.
This means you need to store the previous mouse position for when mouseDragged()
is called.
I implemented something very similar using JOGL instead of Graphics
, using setXORMode(Color color)
. This is also available for the Graphics class. You can read about the XOR mode in the Graphics class here and here.
I don't know how much complexity you're going to put on your project, but if you're anticipating more complexity I would advise using a library like JOGL. It's VERY useful.
UPDATE: Addressing overlapped lines
This is a more challenging task. First, if you're curious and want to fully understand why overlapped lines produce such an intriguing effect, I would advise you to read this.
I guess the only way is to store every line coordinates and redraw them after each new line drawing
This is a very good first approach. Keeping a data structure will all vertices and the shapes they are associated with would allow you to keep calling repaint()
. You must also be aware that in doing so the intersect points will not stand out in your screen (you'll see either one line color or the other, no intermediate colors), but this should already be your intent.
Do you know what a bounding box is? You can create a bounding box for any line (or shape) which is just a rectangle that surrounds your points.
Let's assume you do in fact keep a bounding box for each line. When adding a new line, you could:
- Check if the line you're about to draw intercepts any bounding boxes
- If it does, repaint all lines associated with those bounding boxes
- Add the new line without XOR mode
This technique is better than redrawing the entire screen because there could be an arbitrary number of lines already present, and you can write a decently efficient algorithm to check for bounding box intersections.
Note that intercepting a bounding box does not imply that there is overlapping, because there are some exceptions (e.g. parallel lines) that make this a wrong assumption. Also keep in mind that the only way to avoid seeing line intersections painted with a distinct color due to XOR mode is to draw them without XOR mode. You will have to be very careful toggling XOR mode on and off at the right times.
I found an interesting page about additional ways you could tackle this problem, you can check it here.
回答2:
your problem is this part of your code
public void mouseDragged(MouseEvent me) {
point2 = me.getPoint();
line2d = new Line2D.Double(point1, point2);
draw();
specifically line2d = new Line2D.Double(point1, point2); it's drawing a new line one the mouse is dragged.
来源:https://stackoverflow.com/questions/30661685/drawing-a-line-with-java-swing-draws-multiple-lines