Question

I have two separate class and driver files, and in the class file I create the paint method:

public void paint(Graphics g){
g.drawLine(......
....
//along with all of my other draw commands
}

Further down in the code, I create a JButton and within this button's action listener I don't know how to use a Graphics object to create more graphics in the JFrame. Should I be adding something to my driver to make this happen, or is there a way to use these graphics within my action listener? Thank you, and any help is appreciated.

Was it helpful?

Solution

You need to draw everything within the paint method. The actionPerformed should only change the state of something already in the paint method, and then call repaint. For example

boolean drawHello = true;
boolean drawWorld = false;

protected void paintComponent(Graphics g) {
    super.paintCompoent(g);
    if (drawHello)
             g.drawString("Hello", 50, 50);

    if (drawWorld)
             g.drawString("World", 10, 10);
}

Then in your actionPerformed, you can change the state of drawWorld to true and call repaint().

public void actionPerformed(ActionEvent e) {
    drawWorld = true;
    repaint();
}

So as you can see, everything should be drawn in the paintComponent method. You can just hide and paint renderings, and make them "visible" from a action command. You should already have predefined what could posibly be drawn. Then just change the state of it rendering

And as @MadPrgrammer pointed out, you should not be painting on top-level containers like JFrame. Instead paint on a custom JPanel or JComponent and override the paintComponent method, instead of JFrame and paint

Here's an example where I draw a new square every time the button is pressed. If look at the code, you will see that in the paintComponent method, I loop through a list of Squares and draw them, and in the actionPerformed all I do is add a new Square to the List and call repaint()

enter image description here

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class AddSquares {

    private int R = 0;
    private int G = 0;
    private int B = 0;
    private int xLoc = 0;
    private int yLoc = 0;

    List<Square> squares = new ArrayList<>();
    private JButton addSquare = new JButton("Add Square");
    private RectsPanel panel = new RectsPanel();

    public AddSquares() {

        addSquare.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e) {
                Color color = new Color(R, G, B);
                squares.add(new Square(xLoc, yLoc, color));
                panel.repaint();
                R += 10;
                G += 20;
                B += 30;
                xLoc += 20;
                yLoc += 20;

            }
        });

        JFrame frame = new JFrame("Draw Squares");
        frame.add(panel, BorderLayout.CENTER);
        frame.add(addSquare, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }

    private class RectsPanel extends JPanel {

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (Square square : squares) {
                square.drawSquare(g);
            }
        }

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

    private class Square {
        int x = 0; 
        int y = 0;
        Color color;

        public Square(int x, int y, Color color) {
            this.x = x;
            this.y = y;
            this.color = color;
        }

        public void drawSquare(Graphics g) {
            g.setColor(color);
            g.fillRect(x, y, 75 ,75);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                AddSquares addSquares = new AddSquares();
            }
        });
    }
}

OTHER TIPS

It's difficult to be 100%, but it would seem as you don't understand how custom painting is performed in Swing.

Start by taking a look at Performing Custom Painting and Painting in AWT and Swing.

Essentially, painting is arranged by the Repaint Manager, which decides what and when something should be painted. It then calls (through a chain of methods) the paint method of the components it thinks need to be updated, passing it a reference to a Graphics context that should be used to actually paint on.

Basically, when ever your paint method is called, you should create paint the current state of your painting.

You should avoid overriding paint and instead use paintComponent from classes the extend JComponent

Your question is a little on the vague side as to what you are actually wondering about but generally speaking:

  • We don't override paint in Swing, we override paintComponent.

If you are already aware of this, you may be overriding paint because you are doing it on a JFrame and you found that JFrame does not have a paintComponent method. You shouldn't override paint on a JFrame. Instead, create a JPanel or something to put inside the frame and override paintComponent on the panel.

  • Question about the ActionListener.

It sounds like you are wanting to do painting outside of paintComponent in which case probably the best way is to do painting to a separate Image. Then you paint the Image on to the panel in paintComponent. You can also put an Image in a JLabel as an ImageIcon. Here is a very simple drawing program using MouseListener that demonstrates this (taken from here):

import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;

class PaintAnyTime {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new PaintAnyTime();
            }
        });
    }

    final BufferedImage image = (
        new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB)
    );

    final JFrame frame = new JFrame();

    final JLabel label = new JLabel(new ImageIcon(image));

    final MouseAdapter drawer = new MouseAdapter() {
        Graphics2D g2D;

        @Override
        public void mousePressed(MouseEvent me) {
            g2D = image.createGraphics();
            g2D.setColor(Color.BLACK);
        }

        @Override
        public void mouseDragged(MouseEvent me) {
            g2D.fillRect(me.getX(), me.getY(), 3, 3);
            label.repaint();
        }

        @Override
        public void mouseReleased(MouseEvent me) {
            g2D.dispose();
            g2D = null;
        }
    };

    PaintAnyTime() {
        label.setPreferredSize(
            new Dimension(image.getWidth(), image.getHeight())
        );

        label.addMouseListener(drawer);
        label.addMouseMotionListener(drawer);

        frame.add(label);

        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
}

@MadProgrammer has already linked to the articles that I was going to link to.

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