0

My Problem: The graphics2D object recolors EVERY point in the ArrayList. How would I make it so when I change the color, it doesn't change previous colors? My guess would be to change how the for loops interate in PaintApp, but I'm not sure what I should make it. Thanks for any help!

My Code:

PaintApp.java

package paint;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class PaintApp extends JPanel {

    private List<List<Point>> points;
    private JFrame frame = new JFrame("Sketch MSPaint");
    private JMenuBar bar = new JMenuBar();
    private JMenu file = new JMenu("File");
    private JMenu colors = new JMenu("Colors");
    private JMenuItem quit = new JMenuItem("Quit");

    private JMenuItem red = new JMenuItem("Red");
    private JMenuItem blue = new JMenuItem("Blue");
    private JMenuItem green = new JMenuItem("Green");
    private JMenuItem orange = new JMenuItem("Orange");
    private JMenuItem pink = new JMenuItem("Pink");
    private JMenuItem cyan = new JMenuItem("Cyan");

    private JMenuItem clear = new JMenuItem("Clear");
    private boolean clearBoard = false, blackColor, redColor, blueColor, greenColor, orangeColor, pinkColor, cyanColor;

    
    
    public PaintApp(Dimension d) {
        this.setSize(d);
        this.setPreferredSize(d);

        points = new ArrayList<>();
        MouseAdapter ma = new MouseAdapter() {

            private List<Point> currentPath;

            @Override
            public void mousePressed(MouseEvent e) {
                currentPath = new ArrayList<>();
                currentPath.add(e.getPoint());

                points.add(currentPath);
            }

            @Override
            public void mouseDragged(MouseEvent e) {
                Point dragPoint = e.getPoint();
                currentPath.add(dragPoint);
                repaint();
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                currentPath = null;
            }

        };

        addMouseListener(ma);
        addMouseMotionListener(ma);
    }

    public void paint(Graphics g) {
        super.paint(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.clearRect(0, 0, frame.getWidth(), frame.getHeight());

        for (List<Point> path : points) {
            Point from = null;
            for (Point p : path) {
                if (from != null) {
                    if (redColor) {
                        g2d.setColor(Color.red);
                    } else if (blueColor) {
                        g2d.setColor(Color.blue);
                    } else if (greenColor) {
                        g2d.setColor(Color.green);
                    } else if (orangeColor) {
                        g2d.setColor(Color.orange);
                    } else if (pinkColor) {
                        g2d.setColor(Color.pink);
                    } else if (cyanColor) {
                        g2d.setColor(Color.cyan);
                    } else {
                        g2d.setColor(Color.black);
                    }
                    g2d.drawLine(from.x, from.y, p.x, p.y);
                }
                from = p;
            }
        }
        g2d.dispose();
    }

    public void initBar() {
        bar.add(file);
        file.add(clear);
        clear.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                points = new ArrayList<>();
                repaint();
            }

        });
        file.add(quit);
        quit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.exit(0);

            }

        });

        bar.add(colors);
        colors.add(red);
        red.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = true;
                blueColor = false;
                greenColor = false;
                orangeColor = false;
                pinkColor = false;
                cyanColor = false;
                repaint();
            }

        });

        colors.add(orange);
        orange.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = false;
                blueColor = false;
                greenColor = false;
                orangeColor = true;
                pinkColor = false;
                cyanColor = false;
                repaint();

            }

        });

        colors.add(blue);
        blue.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = false;
                blueColor = true;
                greenColor = false;
                orangeColor = false;
                pinkColor = false;
                cyanColor = false;
                repaint();
            }

        });

        colors.add(green);
        quit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = false;
                blueColor = false;
                greenColor = true;
                orangeColor = false;
                pinkColor = false;
                cyanColor = false;
                repaint();

            }

        });

        colors.add(pink);
        quit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = false;
                blueColor = false;
                greenColor = false;
                orangeColor = false;
                pinkColor = true;
                cyanColor = false;
                repaint();

            }

        });

        colors.add(cyan);
        quit.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent arg0) {
                redColor = false;
                blueColor = false;
                greenColor = false;
                orangeColor = false;
                pinkColor = false;
                cyanColor = true;
                repaint();

            }

        });

        frame.setJMenuBar(bar);

    }

    public void show() {
        frame.add(this);
        initBar();
        frame.setResizable(false);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
}

Main.java

package paint;

import java.awt.Dimension;

public class Main {
    public static void main(String[] args) {
        
        PaintApp app = new PaintApp(new Dimension(700,700));
        
        app.show();
        
    }
}
  • 2
    You should create a custom object that contains all the properties of what you want to paint. In your example your object might contain a Line object and the Color of the object you want to paint. See: [Custom Painting Approaches](https://tips4java.wordpress.com/2009/05/08/custom-painting-approaches/) for a working example. It paints "coloured rectangles", but the concept is the same. – camickr Oct 14 '20 at 01:53
  • *Eventually I do want to add an undo button* - suggestion made in the above link. – camickr Oct 14 '20 at 01:58
  • is this the only way? I'm not quite sure I should paint over a buffered image, as the guy said below, there would be no way to add an undo button, would there? – AbysssCoder Oct 14 '20 at 02:08
  • The link doesn't suggest to use the buffered image approach. It gives another approach including how to use the mouse to draw the rectangles. – camickr Oct 14 '20 at 02:12
  • Abys, @camickr makes suggestion similar to the 2nd part of my answer, the part that avoids use of a BufferedImage. Please re-read both his first comment and my answer. – DontKnowMuchBut Getting Better Oct 14 '20 at 02:12

1 Answers1

1

The easiest solution that I see, if you don't want to give this an "undo" feature, is to draw to a BufferedImage and then display that same BufferedImage within a paintComponent override (not paint -- never paint). This way, the previously drawn lines will persist until you replace the BufferedImage with a new instance.

Else, if you absolutely cannot go this route, then create a new custom class, one that holds a Line2D or other Shape type object and a Color, create these objects when the user draws, store them to a List of such objects, and then paint with them in your (again) paintComponent override. This way you associate each line (or other Shape) with a Color, and the association will persist.

As noted above, I also recommend not overriding paint but rather paintComponent since the latter allows for automatic double buffering should you decide to do animation, and also you don't risk messing with the painting of your component's child components and border, which you risk doing when you override paint. Of course, call the super.paintComponent(g) method in your override, often on its first line.

  • Eventually I do want to add an undo button, so what would be the next best solution? – AbysssCoder Oct 14 '20 at 01:54
  • @AbysssCoder: see edits. Or you *could* save old images to disk if you go the first route. – DontKnowMuchBut Getting Better Oct 14 '20 at 01:55
  • To be honest, one of my friends did the mouse pressed thing, and I vaguely understand it. So how would I do as you suggested? Could you possibly clarify more without giving me the answer? – AbysssCoder Oct 14 '20 at 02:01
  • @AbysssCoder: I'm afraid that it's late and is time for me to go to bed. You might want to get up with that friend who gave you the code for more explanation. My philosophy though has been to avoid borrowing code, but instead to borrow ideas gleaned from other code, and then write my own code based on those ideas. Even if my code isn't great, I understand it a lot better than I would if I just used the other code. This may work well for you in the future. Good luck though. – DontKnowMuchBut Getting Better Oct 14 '20 at 02:07
  • Note that some of your code looks similar to code I've seen here created by MadProgrammer, such as in [this answer](https://stackoverflow.com/a/32981915/7210739). He is a Swing genius and you would do well to search out and fully study his answers related to this assignment. You will learn much from them, I know that I have. – DontKnowMuchBut Getting Better Oct 14 '20 at 02:11