5

I have been searching for a reason for this behavior in my code for quite some time now. I do not want to dive too deeply into the Swing API to figure why this occurs. I would appreciate any information regarding what causes this problem.

This is a simplified version of the application I am writing, the problems seems to be when I click draw the first time, the image will not paint onto the panel, but when I click it the second time, it would paint the image perfectly. Any drawing done after will work correctly, but the initial paint problem is annoying me greatly. Thanks for any help! :)

public class ImageTester {

public static void main(String[] args) {
    final JFrame window = new JFrame("Image Tester");
    final JPanel pane = new JPanel();
    JButton draw = new JButton("Draw");
    JButton paint = new JButton("Paint");

    Toolkit k = Toolkit.getDefaultToolkit();
    final Image i = k.createImage("tester.jpg");
    //pane.getGraphics().drawImage(i, 22, 15, null);

    draw.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent arg0) {
            System.out.println(pane.getGraphics());
            pane.getGraphics().drawRect(5, 5, 15, 15);
            pane.getGraphics().drawImage(i, 15, 15, null);
            System.out.println("Performance");
        }
    });

    paint.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {

        }
    });

    pane.add(draw);
    pane.add(paint);
    window.add(pane);
    window.setVisible(true);
    window.setSize(new Dimension(400, 400));
    window.setLocationRelativeTo(null);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319

3 Answers3

5

Besides the advice of camickr..

Images load asynchronously using Toolkit.createImage(). Either use ImageIO.read(URL/File/InputStream) or add a MediaTracker.


E.G.

On first run I see.

enter image description here

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.net.URL;
import javax.imageio.ImageIO;

public class ImageTester {

public static void main(String[] args) throws Exception {
    final JFrame window = new JFrame("Image Tester");
    JButton draw = new JButton("Draw");
    JButton paint = new JButton("Paint");

    final Image i = ImageIO.read(new URL(
        "http://pscode.org/media/citymorn2.jpg"));

    ImagePanel gui = new ImagePanel();
    gui.setImage(i);
    draw.addActionListener(new ActionListener() {

        public void actionPerformed(ActionEvent arg0) {
        }
    });

    paint.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
        }
    });

    gui.add(draw);
    gui.add(paint);
    window.add(gui);
    window.setVisible(true);
    window.setSize(new Dimension(400, 400));
    window.setLocationRelativeTo(null);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

class ImagePanel extends JPanel {

    Image i;

    public void setImage(Image image) {
        i = image;
    }

    public void paintComponent(Graphics g) {
        //System.out.println(pane.getGraphics());
        super.paintComponent(g);
        g.drawRect(5, 5, 15, 15);
        g.drawImage(i, 15, 15, null);
        System.out.println("Performance");
    }
}
Community
  • 1
  • 1
Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • I thought ImageIO is slower and more costly in term of performance? I am trying to milk out some performance. – JavaMeditator Jan 02 '12 at 06:36
  • @user1125661, I have no idea if your above statement is correct or not, but it is better to learn proper programming techniques before worrying about performance. Using your old approach did you try to resize the frame AFTER clicking on the button to see what happens? – camickr Jan 02 '12 at 06:43
  • This program is just a sample test program to narrow down the problem I have in my application. I understand many of the problems and horrible programming techniques implemented here. Thank you for the tips though! – JavaMeditator Jan 02 '12 at 06:53
1

Don't use the getGraphics() method. That painting will be lost the next time Swing determines a component needs to repaint itself.

Custom painting is done by overriding the paintComponent() method of a JPanel (or JComponent) and then you add the panel to the frame.

See Custom Painting for more information and examples.

camickr
  • 321,443
  • 19
  • 166
  • 288
1

When you use createImage(), the image data is loaded, but it isn't translated into renderable pixels until it knows what component it's going to be drawn on. The Toolkit.prepareImage() method can do this. Add this line to the end of your program, and the paint problem will go away:

k.prepareImage(i, -1, -1, pane);
Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • `prepareImage()` (returns) *"true if the image has already been fully prepared; false otherwise."* Given that implies it is not a blocking method, what is the point of it in this code? – Andrew Thompson Jan 02 '12 at 06:11
  • Thank you for the quick response. It indeed fixed the problem. The explanation is very helpful tool. I'll look more into this as well. Thank you. – JavaMeditator Jan 02 '12 at 06:13
  • @user1125661 This may fix the problem, but it is only a problem because your code uses the wrong approach for custom painting and should not the the solution that you pursue. Combine the suggestions by Andrew and myself for the proper solution. If you use proper painting techniques there is no ned to ever use that method suggested here. – camickr Jan 02 '12 at 06:27
  • +1 for explaning the actual problem, -1 for not suggesting a better custom painting solution. – camickr Jan 02 '12 at 06:33