Millie Millie - 1 month ago 11
Java Question

Simple Paint Program - new line is not being recognized

I have created a simple paint program. All the functionalities are working, but when I go to create a new line, the program does not recognize that it is creating a new line, and instead just creates one huge line. The code will compile if you run it. Any help would be greatly appreciated. Thank you!

Paint Program Output

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;

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();

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

design();

addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
//points.clear();
points.add(e.getPoint());
// repaint();
}

public void mouseReleased(MouseEvent e){
points.add(e.getPoint());

// points.clear();
//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.BLACK;
}

//repaint();
}

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

if(points != null && points.size() > 1){
for(int p = 0; p < points.size() - 1; p++){
int x1 = points.get(p).x;
int y1 = points.get(p).y;
int x2 = points.get(p + 1).x;
int y2 = 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

It looks to me as though you need to be storing the line segments separately rather than in one list of points. To do that you need to define a class to hold them and store a list of segments rather than points.

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<>();

Then create a new segment each time the mouse is pressed and add the point to the current segment each time the mouse is dragged:

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

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

You don't need to do anything when the mouse is released as the point will already have been added on drag. You can delete that listener.

Your paint method then needs to iterate through all segments:

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

    for (Segment segment : segments) {
        g2.setColor(segment.color);
        g2.setStroke(segment.stroke);
        for (int p = 0; p < segment.points.size() - 1; p++) {
            Point p1 = segment.points.get(p);
            Point p2 = segment.points.get(p + 1);
            g2.drawLine(p1.x, p1.y, p2.x, p2.y);
        }
    }
    g2.dispose();
}

I've removed your check to ignore lines with less than two points: the for loop will skip those anyway so it's redundant.

Inserting the new segments at index 0 makes the code to add points simple but has the disadvantage that lines drawn first overwrite later lines. Simple solution would be to use a Deque and peekLast rather than List and get(0).

There are lots of other improvements (particularly performance) you can make but I've tried those changes myself and they work fine.

Screen shot

Comments