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:
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) {
}
}
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
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();
}
}
}