Gabriel
Gabriel

Reputation: 121

can't draw on a JPanel after repaint method

I'm experimenting on a GUI that I programmed and I don't understand how I can fix my problem: My GUI contains a jPanel that on receiving a mouseclick, paints a point with filloval command.

private void myPnlMousePressed(java.awt.event.MouseEvent evt) {                                   
    changed = true;
    p.x = evt.getX();
    p.y = evt.getY();
    drewPoints(p.x, p.y);
} 

private void drewPoints (int x, int y) {
    if (gf == null) {
        gf = (Graphics)myPnl.getGraphics();
    }
    myPointsList.add(new Point(x, y));
    gf.fillOval(x, y, 5, 5);
    xVal.setText("X = " + x);
    yVal.setText("Y = " + y);
}

everything works fine but when I want to open an XML file that I created to save all the points it doesn't work. The problem is that when I use the repaint method on the jPanel after choosing a file, all the points loads fine but the panel can't draw the points. If I put the repaint method in the open button listener (before the choosing file) it works, but then if the user cancels the open option so the panel stays blank and I don't want to draw the points again. I think it happens because the repaint process is not finished. All the points added to a private List.

private void OpenFile() {
    try {
        File thisFile;
        JFileChooser of = new JFileChooser();
        int option = of.showOpenDialog(of);

        if (option == JFileChooser.APPROVE_OPTION){
            thisFileName = of.getSelectedFile().getPath();
            thisFile =  new File(thisFileName);                
            if (!of.getSelectedFile().getName().endsWith(".xml")) {
                String error = "Error, You didn't select XML file";
                JOptionPane.showMessageDialog(this, error, "Wrong type of file", JOptionPane.INFORMATION_MESSAGE);
                return;
            }            
            myPnl.repaint();
            myPointsList.clear();
                        ....
                        ....
                        ....
            for (int i = 0; i < pointsList.getLength(); i++) {
                Element point = (Element) pointsList.item(i);
                p.x = Integer.parseInt(point.getElementsByTagName("X").item(0).getTextContent());
                p.y = Integer.parseInt(point.getElementsByTagName("Y").item(0).getTextContent());
                drewPoints(p.x, p.y);
            }
                        ....

how can I make it work??

Upvotes: 0

Views: 942

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

Don't use gf = (Graphics)myPnl.getGraphics();, this is not how painting in Swing works. The getGraphics method can return null and is nothing more then a snap shot of the last paint cycle, any thing you paint to it will be erased on the next paint cycle (repaint).

Instead, override the JPanels paintComponent and put all you painting logic there. There is an expectation that when called, you are expected to fully re-paint the current state of the component.

See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing

Upvotes: 4

Giulio Biagini
Giulio Biagini

Reputation: 920

You have to use the repaint() and override the paint() method:

class MyPanel extends JPanel implements MouseListener
{
    private int x;
    private int y;

    public MyPanel() {
        super();
        addMouseListener(this);
    }

    @Override public void mouseEntered(MouseEvent e) { }

    @Override public void mouseExited(MouseEvent e) { }

    @Override public void mouseClicked(MouseEvent e) { }

    @Override public void mousePressed(MouseEvent e) { }

    @Override public void mouseReleased(MouseEvent e) {
        x = e.getX();
        y = e.getY();
        repaint();
    }

    @Override public void paint(Graphics g) {
        super.paint(g);
        g.fillOval(x, y, 10, 10);
    }
}

If you want to draw all points, don't use x and y but a list of points:

class MyPanel extends JPanel implements MouseListener
{
    private ArrayList<Point> points = new ArrayList<>();

    public MyPanel() {
        super();
        addMouseListener(this);
    }

    @Override public void mouseEntered(MouseEvent e) { }

    @Override public void mouseExited(MouseEvent e) { }

    @Override public void mouseClicked(MouseEvent e) { }

    @Override public void mousePressed(MouseEvent e) { }

    @Override public void mouseReleased(MouseEvent e) {
        points.add(new Point(e.getX(), e.getY()));
        repaint();
    }

    @Override public void paint(Graphics g) {
        super.paint(g);
        for (Point p : points)
            g.fillOval(p.getX(), p.getY(), 10, 10);
    }
}

where:

class Point
{
    private int x;
    private int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }
}

Then use it:

public static void main(String[] args) {
    JFrame frame = new JFrame("Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 400);
    frame.setLocationRelativeTo(null);

    MyPanel myPanel = new MyPanel();

    frame.add(myPanel);
    frame.setVisible(true);
}

Upvotes: 2

Related Questions