views:

88

answers:

4

I would like to be able to paint Images onto a JFrame, but whenever I want (not in the JFrame.paint method.

For the project I am working on, I have a class Bullseye extends BufferedImage, and am trying to put it onto a JFrame:

class DrawingFrame extends JFrame {
    public void drawImage(Image img, int x, int y) {
        getGraphics().drawImage(img,x,y,null);
        repaint();
    }
}

class Main {
    public static void main(String[] args) {
        DrawingFrame frame = new DrawingFrame();
        Bullseye bullseye = new Bullseye(20,20); //width,height

        // later
        frame.setVisible(true);
        frame.drawImage(bullseye,10,20);
        frame.drawImage(bullseye,20,20);
        frame.drawImage(bullseye,30,20);
    }
}

However, nothing shows up. After some research, apparently this doesn't work because the changes to the graphics object get cleared when I repaint().

How can I do this? Is this even the right approach?

+2  A: 

I think you take the problem backwards. In Swing, all drawing operations should be done within the paint() method.

What you can do is to store the image you want to draw as attribute in your class, then, in your pain method, draw the image wherever you want. For example:

class MyFrame extends JFrame {

    Image image;

    public void paint(Graphics g) {
        super.paint(g);
        if (image != null) {
            g.drawImage(image, /* ... */);
        }
    }

    public void setImage(Image image) {
        this.image = image;
        repaint();
    }

}

And in your other class:

myFrame.setImage(myImage);
Vivien Barousse
The problem with this is that I want to be able to add lots of images at various (x,y) coordinates. With this method, I can only do one. I could make it so it "queues" up images to paint at certain coordinates during the next paint call, but that seems overkill.
Austin Hyde
If you want more images, you can replace the `image` attribute by a `List<Image>`. But if you want to draw directly in a JFrame, you have to override the `paint()` method.
Vivien Barousse
+1  A: 

How about creating a offscreen image to paint on while outside of actual paint, and then the actual paint just paints the offscreen image to actual graphics? A kinda double buffering?

Ashish Patil
+1  A: 

Drawing to the screen in Java is (almost) always done in paint(). What you need for your class is:

class DrawingFrame extends JFrame {

    private Image bullseye = new Bullseye(20,20); //width,height


    public void paint(Graphics g) {
        g.drawImage(bullseye,10,20);
        g.drawImage(bullseye,20,20);
        g.drawImage(bullseye,30,20);
    }

}

class Main {
    public static void main(String[] args) {
        DrawingFrame frame = new DrawingFrame();

        // later
        frame.setVisible(true);
    }
}

If you need to turn on the drawing of bullseyes at a specific time, create a flag on the DrawingFrame object, and set it when you need them. You will need to call repaint() when the flag is set.

DJClayworth
+1  A: 

Custom painting should RARELY ever be done in the paint() method, especially the paint() method of a JFrame. Custom painting is done by overriding the paintComponent() method of a Swing component, generally a JComponent or JPanel. Read the section from the Swing tutorial on Custom Painting for more information and working examples.

However, im this case you don't event need to do any custom painting. You just create an ImageIcon and add the Icon to a JLabel, then you add the JLabel to a panel. Read the section from the Swing tutorial on How to Use Icons for working examples.

If you can't find the appropriate layout manager to use you can also use absolute positioning. Again you will find a section in the tutorial on using layout managers that explains this in more detail.

camickr