I've just started coding video games and I've heard that doing all your drawing on a JPanel and attaching that panel onto a JFrame is better than simply drawing onto the JFrame. I was just wondering why is this better?
-
@mre It is something I commonly recommend (or close to that - see my answer), but am also interested to hear the OP's exact source on that info. To the person asking the question. This would become a 'good question' with that small extra amount of information. – Andrew Thompson Apr 09 '12 at 13:42
-
+1 , one of the few Java questions I know the answer to. Once created a [Java RPG Game](https://github.com/intermediate-hacker/Pro_RPG), thoroughly enjoyed it. :) – ApprenticeHacker Apr 09 '12 at 13:53
3 Answers
It is better for various reasons, including:
- In most Swing components, custom painting is achieved by overriding the
paintComponent(Graphics)
method. Top-level Swing containers (e.g.JFrame
,JApplet
,JWindow
) have onlypaint(Graphics)
. As a result of the common method for painting, people who answer often forget about this difference between common and top-level components, and therefore suggest silly advice. ;) - A
JComponent
can be added to aJFrame
, or aJApplet
, or aJDialog
, or a constraint of a layout in aJPanel
, or aJInternalFrame
, or a.. Just when you think your GUI is complete, the client says "Hey, wouldn't it be great to throw in a tool-bar & offer it as an applet as well?" TheJComponent
approach adapts easily to that. - As explained (complete with code!) by Richante, it is easier to calculate the co-ordinates required for painting the custom component, and if it has a preferred size, to size the
JFrame
to be 'exactly the right size' to contain the GUI (usingpack()
). That is especially the case when other components are added as well.
Now, two minor disagreements with the advice offered.
If the entire component is custom painted, it might be better to simply put a BufferedImage
inside an ImageIcon
/JLabel
combo. Here is an example of painting to an image.
When it comes time to update it:
- Call
getGraphics()
for aGraphics
orcreateGraphics()
for aGraphics2D
- Draw the custom painting to that graphics instance
- Dispose of the graphics instance
- Call
repaint()
on the label.

- 1
- 1

- 168,117
- 40
- 217
- 433
-
1
-
@trashgod Thanks for reminding me. There are some things though, that I do not understand. 1) It seems that the panel UI is obtained from [`JPanel.getUI()`](http://docs.oracle.com/javase/7/docs/api/javax/swing/JPanel.html#getUI%28%29), is that correct? 2) Why would a `JComponent` not (have/have access to) a UI delegate of it's own? 3) Should I start my own question(s) on these matters? – Andrew Thompson Apr 10 '12 at 09:44
-
A `JComponent` has no delegate itself, but it provides some basic infrastructure for subclasses that do. [*How to Write a Custom Swing Component*](http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html) is an example. – trashgod Apr 10 '12 at 17:35
-
Thanks, I saw that article from a link you had posted in one of your earlier answers ( I thought to try trawling 'trashgod+UI+delegate' before asking ;), but cannot say I've (either read it thoroughly or) understood it. I'll look more closely at it. – Andrew Thompson Apr 10 '12 at 17:43
-
1No, I'm too tired & distracted to make good use of your time. I'll keep knocking about here for the moment where I can afford to make mistakes & waste people's time, read the document later, and take it up as a question. Thanks for the offer. :) – Andrew Thompson Apr 10 '12 at 18:00
-
1I recently encountered this interesting [counter-example](http://stackoverflow.com/a/11744971/230513) in which the `JPanel` UI delegate was the problem. Switching to `JComponent` was the solution. – trashgod Aug 12 '12 at 03:14
It is an easy way to do Double Buffering.
Let me elaborate a bit. In video games, to avoid the flicker caused by redrawing and display smoother graphics, people usually use double buffering. They create an offscreen surface, draw everything on that and then display the entire off-screen surface on the screen in one go.
In Java2D and Swing, the easiest way to do this, is to simply do your game sprite drawing on a JPanel, and then add the JPanel to a JFrame.
Secondly, by drawing things on a JPanel, you allow more GUI widgets and other graphical objects to be displayed on the JFrame without having to paint them manually in the game loop. For example buttons, menus, other panels, even other rendering JPanels.
Thirdly, it allows you to use automatically translated co-ordinates for your game. You can draw everything from the top-left to the bottom-right without having to worry about the window manager specific things like window border-widths, task panes, titles etc.!
Moreover, this is not just a convention only used by Game Programmers in Java. Creating a separate Game Board, Render Panel or Graphics Widget is quite popular when programming games using a library with an internal mainloop such as a GUI Toolkit. You can use a User Form in Windows Forms and a Drawing Board in GTK+.

- 21,351
- 27
- 103
- 153
-
Drawing an image on a JPanel and then adding the JPanel to the JFrame is not how to do double-buffering. I'm pretty sure you can double-buffer in a JFrame. – Richante Apr 09 '12 at 13:22
-
@Richante I know very well you can double buffer in a JFrame, what I said was using a JPanel is the _easiest_ way, not the _only_ way to do double-buffering with Java2D and Swing. – ApprenticeHacker Apr 09 '12 at 13:25
-
@Richante also, why isn't it a way to do double-buffering? It's used pretty often for that very purpose. – ApprenticeHacker Apr 09 '12 at 13:27
-
Oh yes, I didn't notice that JPanel was double-buffered by default. You're probably right about that then. – Richante Apr 09 '12 at 13:34
The JFrame includes things like the menu, title bar and border. Therefore, when you refer to coordinates you have to account for these. You might also decide to add a menu bar, or some other components, to the frame. If your painting is all in a JPanel, then this won't change how you need to refer to coordinates.
For example, try:
public class Test extends JFrame {
public Test() {
super();
setVisible(true);
setBounds(100, 100, 200, 100);
}
@Override
public void paint(Graphics g) {
g.fillRect(0, 0, 50, 50);
}
public static void main(String[] args) {
new Test();
}
}
and you will see that the black square is not square! Because (0, 0) is the top left corner of the entire frame, not the corner of the visible area.

- 4,353
- 19
- 23