1

I want to do efficient 2D drawing in Java. I would like to have some kind of surface which I may draw freely without having to let the view hierarchy traverse and update, which may cause stutter.

I have used a JPanel at first and called repaint() but I find it not to be optimal (and it is the reason I ask). The closest thing I have worked with is the Android's SurfaceView and it gives me a dedicated drawing surface.

To achieve this dedicated drawing surface, do I need to use OpenGL or is there any equivalent SurfaceView?

Simon Zettervall
  • 1,764
  • 1
  • 15
  • 31

1 Answers1

4

If you don't need Accelerated Graphics, you can draw onto a BufferedImage with Graphics2D. Once you have your data in the BufferedImage, you can simply paint the BufferedImage onto the component. This will avoid any sort of flickering you are talking about.

Creating the BufferedImage is easy:

int w = 800;
int h = 600;
BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

Then you can draw objects onto it with a graphics context (Possibly in your own render function):

Graphics2D g = bi.createGraphics();
g.drawImage(img, 0, 0, null);
//img could be your sprites, or whatever you'd like
g.dipose();//Courtesy of MadProgrammer
//You own this graphics context, therefore you should dispose of it.

Then when you repaint your component, you draw the BufferedImage onto it as one piece:

public void paintComponent(Graphics g){
    super.paintComponent(g);
    g.drawImage(bi, 0, 0, null);
}

Its sort of like using BufferedImage as a back buffer, and then once you are done drawing to it, you repaint it onto the component.

Joseph Pla
  • 1,600
  • 1
  • 10
  • 21
  • I see, but where and how do I get the BufferedImage and the Graphics2D? Do I ask the system to give me any of those? Do I still use the JPanel and it's paintComponents() method? – Simon Zettervall Aug 06 '13 at 08:20
  • You don't have to. You can simply do a normal paint() – Joseph Pla Aug 06 '13 at 08:24
  • @SimonZettervall You can render to the buffered image's Graphics by call BufferedImage#createGraphics. Make sure you also call Graphics#dispose once your done or you might find that the updates don't render properly. If you want to paint the BufferedImage to the screen, then yes, you will need some kind of component to paint it to, I'm afraid, that's how it works. Ps createGraphics returns Graphics2D – MadProgrammer Aug 06 '13 at 08:30
  • @JosephPla You should be calling super.paintComponent to make sure you don't violate the opacity contract of the component – MadProgrammer Aug 06 '13 at 08:31
  • @MadProgrammer darn, forgot about that. I was in a rush. I'll fix that, thanks! – Joseph Pla Aug 06 '13 at 08:31
  • @JosephPla Thanks for the example code! However, do I need to call repaint() on the JPanel in which the paintComponent(Graphics g) lies in? Or is it only drawn once and then I manipulate the contents of the BufferedImage? I would like to not spam repaint() because as I have understood it, it is not instantaneous but will be issued as soon as possible. – Simon Zettervall Aug 06 '13 at 09:46
  • @Simon Zettervall Exactly. You need to call repaint() on the JPanel whenever you want it "updated". – Joseph Pla Aug 06 '13 at 09:48
  • @SimonZettervall So its going to be changing, you can't only repaint it once, you'll have to constantly repaint it. – Joseph Pla Aug 06 '13 at 09:48
  • @JosephPla I see, but is it possible to achieve the BufferedImage without using repaint()? As I recall it is not instantaneous? – Simon Zettervall Aug 06 '13 at 09:51
  • @SimonZettervall You can technically use panel.paintImmediately(...) but i'm not sure if its thread safe. – Joseph Pla Aug 06 '13 at 09:55
  • @SimonZettervall you can also use repaint(long time) where time is the max time that the system will take to repaint. – Joseph Pla Aug 06 '13 at 09:58
  • @JosephPla Please check this link: http://stackoverflow.com/questions/13453331/repaint-in-java-doesnt-re-paint-immediately. The paints may sometimes not be instantaneous. I want a dedicated drawing surface which I may update myself without calling repaint(). Please check the Android's SurfaceView, that is the only equivalent information I can give you what I want to achieve. – Simon Zettervall Aug 06 '13 at 10:03
  • @SimonZettervall In that case, I would go with JOGL or something. – Joseph Pla Aug 06 '13 at 10:07
  • @JosephPla You have given me a good starting ground and I now know what I am looking for. I will ask a new question that is more specific. – Simon Zettervall Aug 06 '13 at 12:24