Reputation: 1043
I am writing an application which has layers (I used JLayeredPane
) containing two principal layers (JPanel
s). I override the paintComponent
method of the Panel
at the bottom (call it Map) so it paints a Map, and the the paintComponent
method of the one at the top (call it selectionPanel) so it paints a selection of an element.
Here's a summary of the structure:
layers - |-selectionPanel(on top) |-Map (at bottom)
I want the Map to stay static, ie, not to do any repaint (except the initial one) since it does not change.
The trouble is, whenever I call selectionPanel.repaint(), Map gets repainted as well! This is a definitely not efficient.
I think this is due to the eager painting behavior of JLayeredPane
. Is there a way to disable this feature in JLayeredPane?
In case you're interested to see the above effect, I've modified this example:
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/** @see https://stackoverflow.com/q/9625495/230513 */
public class LayerDemo extends JFrame {
private static final Dimension d = new Dimension(320, 240);
public LayerDemo() {
JLayeredPane layers = new JLayeredPane();
layers.setPreferredSize(d);
layers.add(new LayerPanel(1 * d.height / 8), 100);
layers.add(new LayerPanel(2 * d.height / 8), 101);
layers.add(new LayerPanel(3 * d.height / 8), 102);
this.add(layers, BorderLayout.CENTER);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.pack();
this.setLocationByPlatform(true);
}
private static class LayerPanel extends JPanel {
private static final Random r = new Random();
private int n;
private Color color = new Color(r.nextInt());
public LayerPanel(int n) {
this.n = n;
this.setOpaque(false);
this.setBounds(n, n, d.width / 2, d.height / 2);
this.addMouseListener(new MouseHandler(this));
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
color = new Color(r.nextInt());
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, ((float) 20) / 100));
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
g2d.setColor(Color.black);
g2d.drawString(String.valueOf(n), 5, getHeight() - 5);
}
}
private static class MouseHandler extends MouseAdapter {
LayerPanel panel;
MouseHandler(LayerPanel panel) {
this.panel = panel;
}
@Override
public void mouseClicked(MouseEvent e) {
panel.repaint();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
(new LayerDemo()).setVisible(true);
}
});
}
}
Upvotes: 2
Views: 967
Reputation: 324088
Is there a way to disable this feature in JLayeredPane?
If is not a JLayeredPane feature. It is a Swing painting feature.
this.setOpaque(false);
When you make a component non-opaque, then Swing needs to repaint the parent component to make sure the background is painted properly.
In your case it looks like you are using transparency so you would definitely need the background to be repainted.
whenever I call selectionPanel.repaint(), Map gets repainted as well
If you are only painting a certain area of the child panel then you can use:
selectionPanel.repaint(Rectangle)
to minimize the area that is repainted.
color = new Color(r.nextInt());
Don't change the color in the paintComponent() method. This should be done in the MouseListener so it only affects the panel you click on. So even though the other panels will be repainted, their colors will not randomly change.
Upvotes: 2