I have a class that extends JPanel, it contains a draw(Graphics page) method to draw itself.. if I am building a test driver and want to display it on the frame what should I use.. I'm confused between paint(), paintComponent(), getGraphics() etc..
The Class
class Car extends JPanel {
void draw (Graphics page) {
....draw polygons...
}
*EDIT*
The goal is to animate the car moving across the screen, I changed the draw method to 'paintComponent()' and it showed up! But it needs to move it and repaint it with a timer. So I guess painting it over and over again is the reason it's draw() not paintComponent(). ?
paint() AWT containers (use Swing) & Swing top level containers such as JFrame & JApplet (don't paint in top level containers - add a JPanel or JComponent). So basically, don't in this age change the method.
paintComponent() The vast majority of Swing components.
getGraphics() BufferedImage (possibly being displayed in a JLabel). That will provide a Graphics instance, but I prefer using createGraphics() for a Graphics2D instance (rendering hints are wonderful).
Related
How can I use a image as background in a JPanel if the paint () method is already used for other purposes? (I'm tried to draw over a image in a panel).
Here is my code to draw as a pencil, but I donĀ“t know how to add the image as background ?
#Override
public void paint(Graphics g) {
if (x >= 0 && y >= 0) {
g.setColor(Color.BLACK);
g.fillRect(x, y, 4, 4);
}
}
Thanks Diego
Suggestions:
Don't draw in the JPanel's paint(...) method but rather use it's paintComponent(...) method. There are several reasons for this, one being that if you use the paint(...) method, then you are also responsible for drawing the JPanel's borders and child components and at risk of messing up the rendering of these guys. Also you lose Swing's automatic double buffering.
First call the parent class's super method before calling any other code in the method. This will allow the JPanel to refresh its background and do any graphics housekeeping that may need to be done.
Next draw your background image using g.drawImage(...),
Then do your pencil drawing.
Hovercraft Full Of Eels gave good advice on one direction to take. Here is another.
Display the image in a (ImageIcon in a) JLabel.
When it comes time to paint:
Call createGraphics() on the BufferedImage to gain a Graphics2D object.
paint the lines or other visual elements to the graphics instance.
dispose of the graphics instance.
Call repaint() on the label.
E.G. as seen in this answer.
I created a class that extends a JFrame and added a JPanel inside it, but the paintComponents() method doesn't draw anything on the JPanel. Heres the code for the paintComponents(), I chose to use double image buffering.
public void paintComponents(Graphics graphics) {
panel.paintComponents(graphics);
bufferedImage = createImage(sizeX, sizeY);
Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
for (ImageData myImage : imageData) {
g.drawImage(myImage.getImage(), myImage.getX(), myImage.getY(), null);
}
graphics.drawImage(bufferedImage, 0, 0, null);
}
Is there anything wrong with this? Btw, I tried paint() and it worked but I dont think it's the proper way to do this.
Thanks for your time. :)
Do not extend a top level component such as a JFrame. Instead keep an instance of a frame, and add a panel to that. All custom painting or addition of components is done in the panel.
When doing custom painting in a panel, do it in the paintComponent method (not paintComponents do not override that).
Other tips
Remember to call super.paintComponent(g);. This is important to ensure that borders and padding etc. are accounted for.
Swap null for this. Every JComponent is an ImageObserver.
please note that JFrame is NOT a JComponent! In fact, the paintComponents(Graphics) method is NEVER called. A fix would be subclassing JPanel and adding your subclassed panel to the frame as the content pane. In the panel override the paintComponents(Graphics) method.
Let's say we have the following situation:
JPanel panelp=new JPanel();
paintSomething(panelp.getGraphics();
and somewhere else in a different object, the method:
void paintSomething(Graphics g){ /*code*/ }
I don't want to override paintComponent method of panelp. How can I paint something to panelp from the method paintSomething using the Graphics of panelp?
whatever.getGraphics() is snapshot is the snapshot that will go away when
after first repaint
JComponets are repainted internally from Mouse or Key Events, these events are implemented in the concrete JComponets API
simple example for usage of whatever.getGraphics() is printing to the printer or saving current GUI as printscreen to the e.g. JPEG or PGN File
basic stuff is described in the 2D Graphics
You could draw your stuff in the paintSomething into a BufferedImage which you can then draw to the panel by overriding paintComponent
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?
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 only paint(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 a JFrame, or a JApplet, or a JDialog, or a constraint of a layout in a JPanel, or a JInternalFrame, 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?" The JComponent 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 (using pack()). 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 a Graphics or createGraphics() for a Graphics2D
Draw the custom painting to that graphics instance
Dispose of the graphics instance
Call repaint() on the label.
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+.
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.
I have been playing about with some simple painting of Graphics2D and have some extremely good help from the community here.
I managed to get the flickering resolved from my "bouncy balls" by moving the code away from the main JFrame class and into a JPanel which I then added to the JFrame class, can anyone tell me why this would make such a difference?
When you draw in a JComponent's paintComponent method (such as a JPanel's), you use Swing which uses double-buffering when drawing by default. Drawing directly in a JFrame's paint method will only allow AWT type drawing since the JFrame directly inherits from Frame, a heavy weight container, and since AWT graphics does not use double buffering by default and this will lead to choppy animation.