Difference between paint() and paintcomponent()?
Quoting from documentation of paint()
method
This method actually delegates the work of painting to three protected methods: paintComponent, paintBorder, and paintChildren.
...
A subclass that just wants to specialize the UI (look and feel) delegate's paint method should just override paintComponent.
It looks like the paint()
method actually draws the component, including the border and children. If you only want to customize the component's appearance excluding the border and children, you use paintComponent()
.
http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#paint(java.awt.Graphics)
Difference between paint, paintComponent and paintComponents in Swing
- AWT, override
paint()
. - Swing top-level container (e.g.s are
JFrame
,JWindow
,JDialog
,JApplet
..), overridepaint()
. But there are a number of good reasons not to paint in a TLC. A subject for a separate question, perhaps. - The rest of Swing (any component that derives from
JComponent
), overridepaintComponent()
. - Neither override nor explicitly call
paintComponents()
, leave it to the API to call it when needed.
Be sure to also use @Override
notation whenever overriding a method.
Doing so would hint at the problem of trying to override paintComponent(..)
in a JFrame
(it has no such method), which is quite common to see.
Relationship between paint, paintComponent, repaint, etc
Firstly take a look at...
- Performing Custom Painting and
- Painting in AWT and Swing
The second should be compulsory reading for all Swing developers.
paint
is (within the context of this question) the top level method called (update
is actually called first, which just forwards to paint
) when the RepaintManager
wants a component to be painted.
paint
is responsible for (amongst other things) calling paintComponent
, paintBorder
and paintChildren
. If you're not careful you could compromise your components ability to paint. So if you HAVE to override paint
, make sure you are calling super.paint
.
It's important to note, the if a child component is updated, the parent component may not be repainted, so it don't try and use paint
to provide overlays for your component.
paintComponent
is responsible for painting the "background" of the component. This basically delegates to the look and feel.
In the case of something like JPanel
, it will fill the background with the background color (if set to opaque). In the case of something like JTable
, it will paint the rows, columns and cell values.
It is very important to ALWAYS call super.paintComponent
, especially when dealing with transparent components.
repaint
will make a request to the RepaintManager
which may consolidate the paint requests so as to reduce the actual number of paint events that are raised. This helps improve performance.
The important thing to note here is that you don't control the paint process, so don't try, work with it instead.
Your paint
method is also expected to run quickly, so avoid time consuming operations, like loading resources, or compound loops where possible. If you can, create backing buffers and paint those instead
ps- Paint is fun ;)
Paint, repaint , paintComponent
I am not sure about "paint", but I can explain the relationship between repaint() and paintComponent().
In my limited experience with java, the paintComponent() method is a method in the JPanel class and is a member of "swing".
The paintComponent() method handles all of the "painting". Essentially, it draws whatever you want into the JPanel usings a Graphic object.
repaint() is an inherited instance method for all JPanel objects. Calling [your_JPanel_object].repaint() calls the paintComponent() method.
Every time you wish to change the appearance of your JPanel, you must call repaint().
Certain actions automatically call the repaint() method:
- Re-sizing your window
- Minimizing and maximizing your window
to name a few.
IN SHORT paintComponent() is a method defined in JPanel or your own custom class that extends JPanel. repaint() is a method called in another class (such as JFrame) that eventually calls paintComponent().
here is an example:
public class MyPanel extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
g.draw([whatever you want]);
...
...
}
}
public class MyFrame extends JFrame{
public MyFrame(){
MyPanel myPanel = new MyPanel();
myPanel.repaint();
}
}
what is different between paintcomponent() and paintcomponents()?
From a quick browser of the source of java.awt.Container.paintComponents
it seems like it (indirectly) calls paint (after some other processing) on it's child components, and the only reason you'd override it is if you want to do something funky with it. Generally unless you really know what you're doing you probably shouldn't override it and instead should just override paintComponent
on the appropriate control.
Difference between Graphics object of getGraphics and paintComponent
getGraphics
- Can be
null
- Is a "snap shot" of the last paint process
- Anything painted to it will be lost on the next paint cycle
You should avoid using getGraphics
and simply use what is past to the paintComponent
method.
In theory, there is no difference between them, but if you want what you have painted to survive between repaints, then you should be using paintComponent
Updated with example
Without an example code to go by I'm guessing...but...
Basically, this has a JPanel
that acts as the primary "canvas" that draws an image and, when set, a Rectangle
which acts as the selection.
It uses a second class as the MouseListener
to actually make the decisions about what to paint
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MouseSelection {
public static void main(String[] args) {
new MouseSelection();
}
public MouseSelection() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
ImagePane imgPane = new ImagePane();
new MouseHandler(imgPane);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(imgPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class MouseHandler extends MouseAdapter {
private ImagePane imgPane;
private Point clickPoint;
public MouseHandler(ImagePane imgPane) {
this.imgPane = imgPane;
imgPane.addMouseMotionListener(this);
imgPane.addMouseListener(this);
}
@Override
public void mousePressed(MouseEvent e) {
imgPane.clearSelection();
clickPoint = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e) {
clickPoint = null;
}
@Override
public void mouseDragged(MouseEvent e) {
if (clickPoint != null) {
Point dragPoint = e.getPoint();
int x = Math.min(clickPoint.x, dragPoint.x);
int y = Math.min(clickPoint.y, dragPoint.y);
int width = Math.max(clickPoint.x, dragPoint.x) - x;
int height = Math.max(clickPoint.y, dragPoint.y) - y;
imgPane.setSelection(new Rectangle(x, y, width, height));
}
}
}
public class ImagePane extends JPanel {
private BufferedImage img;
private Rectangle selection;
public ImagePane() {
try {
img = ImageIO.read(new File("C:\\hold\\thumbnails\\issue459.jpg"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return img == null ? new Dimension(200, 200) : new Dimension(img.getWidth(), img.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (img != null) {
int x = (getWidth() - img.getWidth()) / 2;
int y = (getHeight() - img.getHeight()) / 2;
g2d.drawImage(img, x, y, this);
}
if (selection != null) {
Color color = UIManager.getColor("Table.selectionBackground");
g2d.setColor(color);
Composite comp = g2d.getComposite();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.fill(selection);
g2d.setComposite(comp);
g2d.draw(selection);
}
g2d.dispose();
}
protected void clearSelection() {
selection = null;
repaint();
}
protected void setSelection(Rectangle rectangle) {
selection = rectangle;
repaint();
}
}
}
Difference between drawing on JPanel via paintComponent and Buffered Image
I found my solution by getting almost every setting of panel graphics and applying them to buffered image graphics. Here, the importing thing is that the panel's graphic scales everything by 1.25 and then scales down to the original before showing it on the panel.
Here is an example, -this is not exactly how my code is, this is just an example to give you an idea-
private void createImages(Paint paint, RenderingHints hints,
AffineTransform transform, Stroke stroke,
Composite composite, GraphicsConfiguration config ){
image = config.createCompatibleImage(IMG_SIZE, IMG_SIZE,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gr = image.createGraphics();
// same options
gr.setPaint(paint);
gr.setRenderingHints(hints);
gr.setTransform(transform);
gr.setStroke(stroke);
gr.setComposite(composite);
//something along the way
gr.drawOval(.....);
gr.drawLine(.....);
gr.drawOval(.....);
panel.repaint();
gr.dispose();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(backgroundColor);
if (USE_BUFFERED_IMAGE) {
Graphics2D g2 = (Graphics2D)g;
createImages(g2.getPaint(), g2.getRenderingHints(),g2.getTransform(),
g2.getStroke(),g2.getComposite(), g2.getDeviceConfiguration());
//scaling down is important because your drawings get scaled to 1.25
// by panels graphics' transformation
g.drawImage(image, startX, startY,(int)(IMG_SIZE*0.8),(int)(IMG_SIZE*0.8), null);
} else {
//something along the way
g.drawOval(.....);
g.drawLine(.....);
g.drawOval(.....);
}
}
Java: Overriding paint() AND paintComponent()
Don't override paint() and don't invoke a painting method directly. The Swing painting mechanism will make sure the proper painting methods are ivoke at the proper time.
Custom painting is done by overriding paintComonent(...)
of a JPanel (or JComponent). Then you add the panel to the frame.
Read the section from the Swing tutorial for more information and working examples.
what does repaint() do?
It schedules a repainting of the component. The RepaintManager
will consolidate repaint requests into a single paint request to make painting more efficient.
You should NEVER invoke repaint() in a painting method. You invoke repaint() in a setter method when you change a property of the class. For example using methods like setForeground(), setBackground() would cause a repaint() of the component.
New to java:
I suggest you keep a link to the Swing tutorial handy for learning Swing basics.
java what is heavier: Canvas or paintComponent()?
The issue is rather broad and the context rather slim.
Consider taking a look at Rotating multiple images causing flickering. Java Graphics2D and Swing animation running extremely slow for example.
The first uses paintComponent
to render up to 10, 000 rotating images at 25fps (or as close as it can).
The second actually animates up to 4, 500 component based images
The ability to paint effectively at this rate is only one consideration to the overall picture
Updated
The primary difference between using a JPanel
and Canvas
is the difference in rendering algorithms.
With a JPanel
you are still at the mercy of the repaint manager. This approach is commonly known as "passive rendering". That is, the manager is responsible for determine what and when something should be painted. Paints are done ad-hoc, when the repaint manager decides something needs to be painted, such as because some OS event has requested that part or whole of the screen should be updated.
Technically, you are not in control of this process and can only simply make requests that a repaint should occur. You may also incur some delays occasionally because the system has butted in and forced an update
Canvas
provides you with a BufferStrategy
, which is more closely tied to the underlying rendering pipeline, potentially, making it faster.
With this, you become responsible for scheduling the repaints. This is commonly known as "active rendering".
You can still but heads with the OS with this approach...
Either way, unless your update/render pipelines are well optimised, you can still run into lots of problems and could actually get better performance from using JPanel
instead of Canvas
Personally, if you're not sure or if you've not done anything like this before, I'd start with JPanel
. Generally, it's slightly simpler to deal with.
I changed the linked example to maintain a FPS counter as well...
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class ZombieLand {
protected static final Random RND = new Random();
private static BufferedImage zombie;
private static int fps = 25;
public static void main(String[] args) {
new ZombieLand();
}
public ZombieLand() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
try {
zombie = ImageIO.read(getClass().getResource("/MiniFig.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
final ZombiePane zombiePane = new ZombiePane();
final JSlider slider = new JSlider(1, 10000);
slider.setMajorTickSpacing(1000);
slider.setMinorTickSpacing(100);
slider.setPaintTicks(true);
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider) e.getSource();
zombiePane.setZombies(slider.getValue());
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(zombiePane);
frame.add(slider, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
slider.setValue(10000);
}
});
}
});
}
public static class ZombiePane extends JPanel {
private List<ZombieSprite> sprites;
protected static final Object SPRITE_LOCK = new Object();
private int desiredCount = 1;
public ZombiePane() {
sprites = new ArrayList<>(25);
sprites.add(new ZombieSprite());
Thread t = new Thread(new GameLoop());
t.setDaemon(false);
t.start();
Font font = getFont();
setFont(font.deriveFont(Font.BOLD, 48f));
}
public void setZombies(int count) {
desiredCount = count;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
synchronized (SPRITE_LOCK) {
for (ZombieSprite sprite : sprites) {
sprite.paint(g2d);
}
}
String text = Integer.toString(sprites.size());
FontMetrics fm = g2d.getFontMetrics();
g2d.drawString(text, getWidth() - fm.stringWidth(text), getHeight() - fm.getHeight() + fm.getAscent());
text = Integer.toString(fps);
g2d.drawString(text, 0, getHeight() - fm.getHeight() + fm.getAscent());
g2d.dispose();
}
protected void cycle() {
synchronized (SPRITE_LOCK) {
if (desiredCount != sprites.size()) {
int count = 0;
int fill = 100;
while (sprites.size() > desiredCount && count < fill) {
sprites.remove(0);
count++;
}
count = 0;
while (sprites.size() < desiredCount && count < fill) {
sprites.add(new ZombieSprite());
count++;
}
}
for (ZombieSprite sprite : sprites) {
sprite.update(getWidth(), getHeight());
}
}
}
public static class ZombieSprite {
private Point motionDelta;
private double rotationDelta;
private Point location;
private double angle;
public ZombieSprite() {
motionDelta = new Point();
motionDelta.x = (int) ((Math.random() * 3) + 1);
motionDelta.y = (int) ((Math.random() * 3) + 1);
if (Math.random() > 0.5) {
motionDelta.x *= -1;
}
if (Math.random() > 0.5) {
motionDelta.y *= -1;
}
rotationDelta = (int) ((Math.random() * 9) + 1);
if (Math.random() > 0.5) {
rotationDelta *= -1;
}
}
public void paint(Graphics2D g2d) {
if (location != null) {
Graphics2D g = (Graphics2D) g2d.create();
AffineTransform at = new AffineTransform();
at.translate(location.x, location.y);
at.rotate(Math.toRadians(angle), zombie.getWidth() / 2, zombie.getHeight() / 2);
g.setTransform(at);
g.drawImage(zombie, 0, 0, null);
g.dispose();
}
}
public void update(int width, int height) {
if (location == null) {
angle = (Math.random() * 360d);
location = new Point();
location.x = (int) (Math.random() * (width - zombie.getWidth()));
location.y = (int) (Math.random() * (height - zombie.getHeight()));
} else {
angle += rotationDelta;
location.x += motionDelta.x;
location.y += motionDelta.y;
if (location.x < 0) {
location.x = 0;
motionDelta.x *= -1;
} else if (location.x + zombie.getWidth() > width) {
location.x = width - zombie.getWidth();
motionDelta.x *= -1;
}
if (location.y < 0) {
location.y = 0;
motionDelta.y *= -1;
} else if (location.y + zombie.getHeight() > height) {
location.y = height - zombie.getHeight();
motionDelta.y *= -1;
}
}
}
}
public class GameLoop implements Runnable {
private long last;
private long start;
private int wait;
private boolean keepRunning = true;
public void run() {
// Calculate the optimal/maximum delay time
// This is converted to nanos so it can be
// used to calculate the actual delay...
long millisPerSecond = TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
long optimalDelay = Math.round(millisPerSecond / 25);
optimalDelay = TimeUnit.MILLISECONDS.toNanos(optimalDelay);
// Last start of a "second" loop
long loop = System.nanoTime();
int frameCount = 0;
// While gaming...
while (keepRunning) {
// Start of this cycle...
long now = System.nanoTime();
// Update the state and render the
// current frame...
cycle();
repaint();
// How long did that update take??
long timeTaken = System.nanoTime();
long delta = timeTaken - now;
// Subtract the delay from the maximum delay
long delay = optimalDelay - delta;
if (delay > 0) {
try {
// Sleep expects milliseconds...
delay = TimeUnit.NANOSECONDS.toMillis(delay);
Thread.sleep(delay);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
// Calculate if we've being running for a second yet...
long loopDelay = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - loop);
// If the loop has been cycling for a second...
if (loopDelay >= 1) {
// Reset the loop time
loop = System.nanoTime();
System.out.println("FPS = " + frameCount);
fps = frameCount;
frameCount = 0;
} else {
// Add another frame to the pile...
frameCount++;
}
}
}
}
}
}
Related Topics
Dynamically Find the Class That Represents a Primitive Java Type
How to Use the Unsigned Integer in Java 8 and Java 9
How to Achieve Transfer File Between Client and Server Using Java Socket
Location of Hibernate.Cfg.Xml in Project
Messagebodyprovidernotfoundexception While Running Jar from Command Line
How to Pass an Integer Class Correctly by Reference
Receiving "Wrong Name" Noclassdeffounderror When Executing a Java Program from the Command-Line
How to Redirect Processbuilder's Output to a String
Java Date Cut Off Time Information
Service Layer and Controller: Who Takes Care of What
Gson.Tojson() Throws Stackoverflowerror
Iteratively Compute the Cartesian Product of an Arbitrary Number of Sets