Question

Im making a small painting program that basically has buttons on the left, indicating the colors, and wherever you click and drag, it'll draw a circle using graphics. i know, not efficient at all, and i can be using strokes and stuff, but im still learning and didn't get to that yet, so im testing it out with what i know. Everything seems to be working, with one small problem. I can click, drag, and a line is drawn. But when i change the color, and go draw something else, the first circle drawn is the previous color. I have tried many things but cant seem to fix it.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;


public class painting extends JFrame{

ArrayList<Integer> mouseLocXList = new ArrayList<Integer>();
ArrayList<Integer> mouseLocYList = new ArrayList<Integer>();
ArrayList<Color> colors = new ArrayList<Color>();
Color colorChosen = Color.black;

String[] colorsSideBarButtonString = {"Red", "Blue", "Green", "Orange", "Pink"};
Color[] colorsSideBar = {Color.red, Color.blue, Color.green, Color.orange ,  
    Color.pink};                          
JButton[] buttons = new JButton[colorsSideBarButtonString.length];


public painting(){
    setSize(1200,700);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setLocationRelativeTo(null);
    setBackground(Color.WHITE);
    setLayout(null);
    setFocusable(true);

    addMouseMotionListener(new handler());

    colors.add(Color.black);

    for(int x = 0; x < colorsSideBarButtonString.length; x++){
        buttons[x] = new JButton(colorsSideBarButtonString[x]);
        buttons[x].setBounds(2,(x*50)+30,70,46);
        add(buttons[x]);
        buttons[x].addActionListener(new buttonListener());
    }

    setVisible(true);
}

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

public void paint(Graphics g){
    super.paint(g);

    g.setColor(Color.black);
    g.drawLine(72, 0, 72, 900);
    g.drawLine(1150, 0, 1150, 900);
    g.drawString("Colors", 17, 45);

    for(int i = 0; i < mouseLocXList.size(); i++){
        g.setColor(colors.get(i));
        g.fillOval(mouseLocXList.get(i),mouseLocYList.get(i),30,30);
    }

}

public class handler implements MouseMotionListener{

    public void mouseDragged(MouseEvent e) {
        mouseLocXList.add(e.getX());
        mouseLocYList.add(e.getY());
        colors.add(colorChosen);
        repaint();
    }
    public void mouseMoved(MouseEvent e) {          
    }

}

public class buttonListener implements ActionListener{

    public void actionPerformed(ActionEvent e) {
        for(int c = 0; c < buttons.length; c++)
            if(e.getSource() == buttons[c]){
                colorChosen = colorsSideBar[c];
        }
    }

}


}

Sorry the programs kinda long, i dont see where i can shorten it, everything seems necessary. Basically every time the mouse is clicked and dragged, its location is stored in an array, where its then drawn in a for loop in graphics. The color is clicked, and added to its own array, and every update to the mouses location while dragged, the current color is added to the colors array so it can be redrawn in color while in the for loop. I would think the best way to fix the problem is to run it.

Once again, i know this is probably one of the worst written programs you've ever seen. I understand, but i am just testing out and trying to see how advanced i can make this.

Was it helpful?

Solution

Painting is destructive, that is, each time paint is called, it will clear/remove what ever was painted before it.

This is very important, as the Graphics context is shared by all the components that are painted during the paint cycle, meaning, when it gets to you, it might already have something painted on it.

You need to do two things.

First, you need to create something that is paintable, that is, some kind of object which provides a simple paint or draw method which you can pass the Graphics context to. This object should know what it's painting and in what color

Second, you need to add each of these "paintable" objects to a List of some kind as they are created. This will allow you to loop through the List and repaint them when you need to.

You should avoid overriding paint of top level containers like JFrame, apart from the fact that they aren't double buffered and can produce flickering when updated, you could end up painting under the borders of the frame's decorations (0x0 is actually the top left of the window/frame, not the viewable area under the frame's title bar).

Instead, use a JPanel and override it's paintComponent method

Take a look at Performing Custom Painting and Painting in AWT and Swing for more details

Updated...

You color list is out of sync with your mouse points because you did...

colors.add(Color.black);

In the constructor. This means that the first circle will be painted in black and the next in the selected color. When you change colors, it is still out of sync

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top