0

I have a Java paint program, and I've got two problems to do with it. Both problems are relatively simple, and just regard how the mouse input is handled and how the image uses colors. Here's a photo of the app:

enter image description here

So here's my first problem:

As you can see, by the look of the app, there's a spray of dots on the paint area. Each of those dots is a mouseclick. The program does not recognize when a user is holding down the mouse button, so you have to click individually.

This is obviously counterproductive, user-unfriendly and unacceptable. Now, how I fix this, I'm not sure. I've tried using a permanent while (true) loop, but that does not work. How do I make it so that instead of having to click every time, each time the mouse is held down it sprays out dots?

The second problem is the color of the dots. As you can see, at the bottom, there are color buttons. These function, but there is a problem: Whenever I change the color, all the dots currently on the screen change color. The color is run by a variable called currentColor which is run by the actionListeners controlled by all the color buttons on the bottom panel. How do I make sure that colors already placed on the screen are not affected anymore?

I believe that all the code that can be fixed for these two problems lies in my custom JPanel which is used for the program to paint on. I'll post the entire class below, and if you have any other questions, please let me know.

int xCord, yCord;

public class PaintPanel extends JPanel implements MouseListener {
    // default serial whatever...
    private static final long serialVersionUID = -6514297510194472060L;

    public PaintPanel() {
        addMouseListener(this);
    }

    ArrayList<Point> points = new ArrayList<Point>();

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Point point : points) {
            g.setColor(currentColor);
            g.fillOval(point.x, point.y, 12, 12);

        }
        repaint();
    }

    @Override
    public void mouseClicked(MouseEvent m) {
    }

    @Override
    public void mouseEntered(MouseEvent m) {
    }

    @Override
    public void mouseExited(MouseEvent m) {
    }

    @Override
    public void mousePressed(MouseEvent m) {

        if (paintPanel.contains(m.getPoint())) {
                points.add(m.getPoint());
                xCord = m.getX();
                yCord = m.getY();
                System.out.println("x: " + xCord + " y: " + yCord);
        }

    }

    @Override
    public void mouseReleased(MouseEvent m) {
    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
user2398233
  • 137
  • 1
  • 2
  • 10
  • Start by taking a look at [How to write Mouse-Motion Listener](http://docs.oracle.com/javase/tutorial/uiswing/events/mousemotionlistener.html) – MadProgrammer Jun 04 '13 at 03:38
  • 2
    Lord, don't ever call `repaint()` from inside of `paintComponent(...)`. Ever. I mean EVER. – Hovercraft Full Of Eels Jun 04 '13 at 03:41
  • @HovercraftFullOfEels I've heard that before. Can you explain to me why, or give me a link, or something? It would save me a lot of time. Thanks. – user2398233 Jun 04 '13 at 03:45
  • 1
    The `paintComponent(...)` method is for one purpose, for painting the component, and that's it. You do not have control over when it is called, if it is called, how often, etc. All you can do is suggest that it might be called via `repaint()`. You don't ever want to slow it down as it will significantly reduce the responsiveness of your program. You should not use it for program logic or for your program or game loop (which is what you are trying to do by calling `repaint()` inside of it). – Hovercraft Full Of Eels Jun 04 '13 at 03:47
  • 1
    @user2398233 Here's [why](http://stackoverflow.com/questions/16904768/why-doesnt-this-java-paint-program-paint-more-than-one-oval?answertab=oldest#tab-top)...from your earlier post – Reimeus Jun 04 '13 at 03:47
  • Indeed, 1+ to @Reimeus's previous answer! – Hovercraft Full Of Eels Jun 04 '13 at 03:55
  • to make it simple what you want to do is have a boolean set to true when the mouse is clicked and false when it is released. then in your main game loop you want to paint. this way it inst dependent on an action event. – Anthony Raimondo Jun 04 '13 at 04:00

1 Answers1

1

Painting in Swing is destructive.

That is to say, when Swing requests that a repaint occur on a component, the component is expected to clear what ever was previously paint and update itself.

The problem with your color issue is that you only ever have a single color specified.

A possible solution would be to paint to backing buffer (like BufferedImage) instead of relying on paintComponent.

Instead of repainting all the dots each time paintComponent is called, you would simply paint the BufferedImage instead.

As to your issue with the mouse, you need to implement a MouseMotionListener, this will allow you to detect when the mouse is dragged across the surface, painting a trail of dots

Update with very BASIC example

enter image description here

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.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SimplePaint04 {

    public static void main(String[] args) {
        new SimplePaint04();
    }

    public SimplePaint04() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private PaintPane paintPane;

        public TestPane() {
            setLayout(new BorderLayout());
            add((paintPane = new PaintPane()));
            add(new ColorsPane(paintPane), BorderLayout.SOUTH);
        }
    }

    public class ColorsPane extends JPanel {

        public ColorsPane(PaintPane paintPane) {
            add(new JButton(new ColorAction(paintPane, "Red", Color.RED)));
            add(new JButton(new ColorAction(paintPane, "Green", Color.GREEN)));
            add(new JButton(new ColorAction(paintPane, "Blue", Color.BLUE)));
        }

        public class ColorAction extends AbstractAction {

            private PaintPane paintPane;
            private Color color;

            private ColorAction(PaintPane paintPane, String name, Color color) {
                putValue(NAME, name);
                this.paintPane = paintPane;
                this.color = color;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                paintPane.setForeground(color);
            }

        }

    }

    public class PaintPane extends JPanel {

        private BufferedImage background;

        public PaintPane() {
            setBackground(Color.WHITE);
            setForeground(Color.BLACK);
            MouseAdapter handler = new MouseAdapter() {

                @Override
                public void mousePressed(MouseEvent e) {
                    drawDot(e.getPoint());
                }

                @Override
                public void mouseDragged(MouseEvent e) {
                    drawDot(e.getPoint());
                }

            };
            addMouseListener(handler);
            addMouseMotionListener(handler);
        }

        protected void drawDot(Point p) {
            if (background == null) {
                updateBuffer();;
            }

            if (background != null) {
                Graphics2D g2d = background.createGraphics();
                g2d.setColor(getForeground());
                g2d.fillOval(p.x - 5, p.y - 5, 10, 10);
                g2d.dispose();
            }
            repaint();
        }

        @Override
        public void invalidate() {
            super.invalidate();
            updateBuffer();
        }

        protected void updateBuffer() {

            if (getWidth() > 0 && getHeight() > 0) {
                BufferedImage newBuffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
                Graphics2D g2d = newBuffer.createGraphics();
                g2d.setColor(Color.WHITE);
                g2d.fillRect(0, 0, getWidth(), getHeight());
                if (background != null) {
                    g2d.drawImage(background, 0, 0, this);
                }
                g2d.dispose();
                background = newBuffer;
            }

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            if (background == null) {
                updateBuffer();
            }
            g2d.drawImage(background, 0, 0, this);
            g2d.dispose();
        }
    }
}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366