Millie Millie - 29 days ago 11
Java Question

Paint Program: Array is writing backwards to the panel

I posted this code earlier, and got a very good answer, but not a working answer. Could someone please show me how to change my code in order to get this fixed? This will run and compile. It is supposed to draw a line on top of a line, but instead it is drawing under the previous line. I have tried using Collections.reverse(segments); but it doesn't take care of element at zero. I also have tried changing to segments.add(new Segment()); but I am not sure what to change in MouseMotionListener to get this to work accordingly. Any help with this would be great! Thank You! :)

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;

public class SimplePaint extends JFrame implements ActionListener {

private static final long serialVersionUID = 1L;
JButton action = new JButton();
JButton red = new JButton();
JButton blue = new JButton();
JButton yellow = new JButton();
Color initial = Color.MAGENTA;
JButton thin = new JButton();
JButton medium = new JButton();
JButton thick = new JButton();
Stroke stroke = new BasicStroke(3);
private static ArrayList<Point> points = new ArrayList<Point>();

JButton erase = new JButton();
JButton drawing = new JButton();
Point start = null;
Point end = null;
Line2D draw = new Line2D.Float();
JPanel panel = new JPanel();

private class Segment {
private final List<Point> points = new ArrayList<Point>();
private final Color color = initial;
private final Stroke stroke = SimplePaint.this.stroke;
}

private final List<Segment> segments = new ArrayList<>();

public SimplePaint() {
getContentPane().add(panel);
setSize(450, 450);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

design();

addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
segments.add(0, new Segment());
}
});

addMouseMotionListener(new MouseMotionAdapter() {
public void mouseDragged(MouseEvent e) {
segments.get(0).points.add(e.getPoint());
repaint();
}
});

addMouseMotionListener(new MouseMotionAdapter(){

@Override
public void mouseDragged(MouseEvent e){
points.add(e.getPoint());
repaint();
}
});

blue.addActionListener(this);
red.addActionListener(this);
yellow.addActionListener(this);
thin.addActionListener(this);
medium.addActionListener(this);
thick.addActionListener(this);
erase.addActionListener(this);
drawing.addActionListener(this);
}

public void design() {
panel.setBackground(Color.BLACK);

blue.setBackground(Color.BLUE);
blue.setPreferredSize(new Dimension(50, 25));
panel.add(blue);

red.setBackground(Color.RED);
red.setPreferredSize(new Dimension(50, 25));
panel.add(red);

yellow.setBackground(Color.yellow);
yellow.setPreferredSize(new Dimension(50, 25));
panel.add(yellow);

thin.setText("Thin");
panel.add(thin);

medium.setText("Medium");
panel.add(medium);

thick.setText("Thick");
panel.add(thick);

erase.setText("Erase");
panel.add(erase);

drawing.setText("Draw");
panel.add(drawing);
}

public void actionPerformed(ActionEvent e) {
if(e.getSource() == blue){
initial = Color.BLUE;
}else if(e.getSource() == red){
initial = Color.RED;
}else if(e.getSource() == yellow){
initial = Color.YELLOW;
}else if(e.getSource() == thin){
stroke = new BasicStroke(1);
}else if(e.getSource() == medium){
stroke = new BasicStroke(5);
}else if(e.getSource() == thick){
stroke = new BasicStroke(10);
}else if(e.getSource() == erase){
initial = Color.WHITE;
stroke = new BasicStroke(15);
}

//repaint();
}

@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;

int x1, y1, x2, y2;

for (Segment segment : segments) {
g2.setColor(segment.color);
g2.setStroke(segment.stroke);

for (int p = 0; p < segment.points.size() - 1; p++) {
x1 = segment.points.get(p).x;
y1 = segment.points.get(p).y;
x2 = segment.points.get(p + 1).x;
y2 = segment.points.get(p + 1).y;
g2.drawLine(x1, y1, x2, y2);


}

}
g2.dispose();

}

public static void main(String []args){
SimplePaint s = new SimplePaint();
s.setVisible(true);
}
}

Answer

To fix your issue, you need to add to the end of the List and not the beginning:

addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        segments.add(new Segment());
    }
});

addMouseMotionListener(new MouseMotionAdapter() {
    @Override
    public void mouseDragged(MouseEvent e) {
       segments.get(segments.size() - 1).points.add(e.getPoint());
       repaint();
    }
});

Additionally, the second mouseDragged() implementation appears redundant, if you remove it, it still functions as expected.

// Can be removed
addMouseMotionListener(new MouseMotionAdapter() {    
    @Override
    public void mouseDragged(MouseEvent e) {
        points.add(e.getPoint());
        repaint();
    }
});

Also, you should really use a JComponent or JPanel to paint your sketch, @Override paintComponent() as opposed to paint() with this approach. This will help (or should completely) remove the flickering you see. Coupled with a javax.swing.Timer to repaint() as opposed to dragging which could update extremely (and unnecessarily) quickly.

Finally, you should ensure your GUI is running on the event dispatch thread using SwingUtilities.invokeLater(Runnable doRun), since Swing objects are not thread safe.

e.g.

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            SimplePaint s = new SimplePaint();
            s.setVisible(true);
        }
    });
}
Comments