Difference Between Paint() and Paintcomponent()

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 ..), override paint(). 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), override paintComponent().
  • 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...

Sample Image

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...

MiniFig

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



Leave a reply



Submit