I was trying to draw simple shapes on a canvas in java (using Eclipse). The canvas appears of the right size and color. The shapes however appear only for a second and then disappear. When they appear they have the correct size, color and location, but they disappear after a second or so. It seems that a line is missing from the below code I wrote, but I can't figure out what it is.
import java.awt.*;
import java.awt.geom.Ellipse2D;
import javax.swing.*;
/**
* Draws simple shapes
*/
public class SimpleDraw2 {
private JFrame frame;
private static Canvas canvas;
private Container contentPane;
private static Graphics graphics;
private Ellipse2D.Double circle;
/**
* Constructor
* Creates canvas and frame
*/
public SimpleDraw2() {
frame = new JFrame("Draw picture");
contentPane = frame.getContentPane();
canvas = new Canvas();
canvas.setSize(250, 250);
canvas.setBackground(Color.YELLOW);
canvas.setForeground(Color.BLUE);
contentPane.add(canvas);
frame.pack();
frame.setVisible(true);
}//end constructor
/**
* Draws two circles
* #param g
*/
public void paint(Graphics g){
circle = new Ellipse2D.Double(125, 125, 50, 50);
g = canvas.getGraphics();
if(g != null){
((Graphics2D) g).fill(circle);
g.setColor(Color.GREEN);
g.fillOval(0, 0, 50, 50);
}
}//end method
/**
* #param args
*/
public static void main(String[] args) {
SimpleDraw2 draw = new SimpleDraw2();
draw.paint(graphics);
}//end main
}//end class
Ah... in the SimpleDraw2.paint() method you get the canvas and then call its paint() method.
You should not do that. Ignore SimpleDraw2.paint() and instead post your paint code inside the canvas.paint() method. This way it will get drawn properly.
Painintg to canvas inside SimpleDraw2.paint() will in fact draw to the canvas, but as soon as that repaints itself, all shapes will be cleared.
Btw dont call paint(Graphics) directly, as you do it in the main() method, rather call repaint()
[UPDATED]
Oh almost forgot... usually you should put your code into the paintComponent() method. See the four test classes.
In v1, the canvas object you create is drawn above the paintings. I don't exactly know what content pane drawing changes in the drawing cycle, along with painting child components, and/or layout managers. That might be one of the reasons why, even though we don't call super.paint(), the canvas still gets painted.
V2 (and v4) gives you maximum control over your paint cycle, and using double/multiple buffering gets a lot easier this way.
V3 is easiest, just straight painting to the main frame, not having any variables or special magic.
In v4, you can also interface that callback(s). Gives you good control and is quite simple too.
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.WindowConstants;
public class GraphicsPaint {
public static void main(final String[] args) {
new SimpleDraw2v1();
new SimpleDraw2v2();
new SimpleDraw2v3();
new SimpleDraw2v4();
}
}
class SimpleDraw2v1 {
private final JFrame frame;
private static Canvas canvas;
private final Container contentPane;
private static Graphics graphics;
private Ellipse2D.Double circle;
/**
* Constructor
* Creates canvas and frame
*/
public SimpleDraw2v1() {
frame = new JFrame("Draw picture");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); // important
contentPane = frame.getContentPane();
canvas = new Canvas();
canvas.setSize(250, 250);
canvas.setBackground(Color.YELLOW);
canvas.setForeground(Color.BLUE);
contentPane.add(canvas);
frame.pack();
frame.setVisible(true);
}//end constructor
/**
* Draws two circles
* #param g
*/
public void paint(final Graphics g) {
circle = new Ellipse2D.Double(125, 125, 50, 50);
final Graphics2D g2 = ((Graphics2D) g);
g2.fill(circle);
g2.setColor(Color.GREEN);
g2.fillOval(0, 0, 50, 50);
}//end method
}//end class
class SimpleDraw2v2 extends JFrame {
private static final long serialVersionUID = 2057752114790427629L;
public SimpleDraw2v2() {
setTitle("Painting v2");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setContentPane(new MyDrawPanel());
setBounds(200, 200, 800, 600);
setVisible(true);
}
}
class MyDrawPanel extends JPanel {
private static final long serialVersionUID = 6483380689207640805L;
#Override public void paint(final Graphics pG) {
// this call (or not overwriting paint() in the first place) results in
super.paint(pG);
// these three calls, in this order. you can test it
// paintComponent(pG);
// paintBorder(pG);
// paintChildren(pG);
final Double circle = new Ellipse2D.Double(125, 125, 50, 50);
final Graphics2D g2 = ((Graphics2D) pG);
g2.fill(circle);
g2.setColor(Color.GREEN);
g2.fillOval(0, 0, 50, 50);
}
#Override protected void paintComponent(final Graphics pG) {
System.out.println("MyDrawPanel.paintComponent()");
super.paintComponent(pG);
}
#Override protected void paintBorder(final Graphics pG) {
System.out.println("MyDrawPanel.paintBorder()");
super.paintBorder(pG);
}
#Override protected void paintChildren(final Graphics pG) {
System.out.println("MyDrawPanel.paintChildren()");
super.paintChildren(pG);
}
}
class SimpleDraw2v3 extends JFrame {
private static final long serialVersionUID = 2057752114790427629L;
public SimpleDraw2v3() {
setTitle("Painting v3");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setBounds(200, 200, 800, 600);
setVisible(true);
}
#Override public void paint(final Graphics pG) {
super.paint(pG);
final Double circle = new Ellipse2D.Double(125, 125, 50, 50);
final Graphics2D g2 = ((Graphics2D) pG);
g2.fill(circle);
g2.setColor(Color.GREEN);
g2.fillOval(0, 0, 50, 50);
}
}
class SimpleDraw2v4 extends JFrame {
private static final long serialVersionUID = 2057752114790427629L;
public SimpleDraw2v4() {
setTitle("Painting v4");
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setContentPane(new JPanel() {
private static final long serialVersionUID = -8011251549484904282L;
#Override public void paint(final Graphics pG) {
super.paint(pG);
paintShapes((Graphics2D) pG); // use this call
}
#Override protected void paintComponent(Graphics pG) {
super.paintComponent(pG);
paintShapes((Graphics2D) pG); // or this call
}
});
setBounds(200, 200, 800, 600);
setVisible(true);
}
protected void paintShapes(final Graphics2D pG) {
final Double circle = new Ellipse2D.Double(125, 125, 50, 50);
pG.fill(circle);
pG.setColor(Color.GREEN);
pG.fillOval(0, 0, 50, 50);
}
#Override public void paint(final Graphics pG) {
super.paint(pG);
}
}
Thanks, Jay! Versions 2 to 4 work well. Version 1 still gave blank canvas. Took me a while to figure it out, but eventually I got it working. Turns out I should have used overridden update() instead of paint(). So here is the code that puts ellipses with coordinates and height width chosen by input into the yellow canvas:
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Ellipse2D;
import java.util.Scanner;
/**
* Draws simple shapes
*/
public class SimpleDraw5 {
private Frame frame;
private static MyCanvas canvas;
private static Graphics graphics;
private Panel panel;
Ellipse2D.Double circle;
/**
* Draws blue ellipses on yellow canvas
* #param args
*/
public static void main(String[] args) {
SimpleDraw5 draw = new SimpleDraw5();
Scanner scan = new Scanner(System.in);
draw.addShapes();
int test;
boolean exit = false;
while (exit == false){
System.out.println("Draw another?");
System.out.println("Enter 1 to keep drawing, 2 to close window "
+ "3 to stop but keep window open>");
test = scan.nextInt();
if(test == 1){
draw.addShapes();
}
else if (test == 2)
System.exit(0);
else
exit = true;
}
}//end main
/**
* Constructor
* Creates canvas and frame
*/
public SimpleDraw5() {
frame = new Frame("Draw picture");
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
} } );
panel = new Panel();
frame.add(panel);
canvas = new MyCanvas();
panel.add(canvas);
frame.pack();
frame.setVisible(true);
}
public void addShapes(){
canvas.update(canvas.getGraphics());
frame.pack();
frame.setVisible(true);
}
/**
* Returns circle set with paramenters
* #param x - X coordinate
* #param y - Y coordinate
* #param height
* #param width
* #return - object of class Ellipse2D.Double
*/
public static Ellipse2D.Double getCircle(int x, int y, int height, int width){
Ellipse2D.Double circle = new Ellipse2D.Double(x,y,height, width);
return circle;
}//end method
/**
* Returns "default" circle
* #return - object of class Ellipse2D.Double
*/
public static Ellipse2D.Double getCircle(){
Ellipse2D.Double circle = new Ellipse2D.Double(0,0,50, 50);
return circle;
}//end method
/**
* Inner class- defines canvas
*
*/
class MyCanvas extends Canvas{
private static final long serialVersionUID = 1L;
private Ellipse2D.Double circle;
/**
* Constructor. Sets canvas size and colors
*/
public MyCanvas(){
setSize(250, 250);
setBackground(Color.YELLOW);
setForeground(Color.BLUE);
}//end
/* (non-Javadoc)
* #see java.awt.Canvas#paint(java.awt.Graphics)
*/
public void paint(Graphics g){
super.paint(g);
frame.setVisible(true);
}//end method
/* (non-Javadoc)
* #see java.awt.Canvas#update(java.awt.Graphics)
*/
public void update(Graphics g){
g = this.getGraphics();
g.setColor(Color.BLUE);
Scanner scan = new Scanner(System.in);
System.out.println("Enter x");
int x = scan.nextInt();
System.out.println("Enter y");
int y = scan.nextInt();
System.out.println("Enter w");
int w = scan.nextInt();
System.out.println("Enter h");
int h = scan.nextInt();
Ellipse2D.Double circle = getCircle(x,y,w,h);
((Graphics2D) g).fill(circle);
((Graphics2D) g).draw(circle);
graphics = g;
}//end method
}//end inner class
}//end class
Related
The JFrame and JPanel show up, but the paintComponent method isn't drawing on the JPanel. I only see the JLabel, JTextField and JButton that I added but not what should be drawn on the JPanel.
update; question has been answered: The circles actually were being drawn to the JPanel but I got the coordinates wrong so they were being drawn outside of the frame.
JFrame class:
package h02;
import javax.swing.*;
public class Circles extends JFrame {
public Circles() {
// JFrame and its properties
JFrame frame = new JFrame();
frame.setSize(500,500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(100, 100);
frame.setTitle("Circles");
frame.add(new CirclesPanel());
frame.setVisible(true);
}
public static void main(String[] args) {
new Circles();
}
}
JPanel class:
package h02;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class CirclesPanel extends JPanel implements ActionListener {
// Fields
private JTextField enterDiameter;
private JButton drawButton;
private int diameter;
private final int Y = 470;
// making the panel
public CirclesPanel() {
enterDiameter = new JTextField("100", 5);
enterDiameter.addActionListener(this);
drawButton = new JButton("Teken");
drawButton.addActionListener(this);
add(new JLabel("Diameter"));
add(enterDiameter);
add(drawButton);
}
// find the diameter
public void findDiameter() {
int diameterString = Integer.parseInt(enterDiameter.getText());
diameter = diameterString;
}
// draw circles
public void paintComponent(Graphics g) {
super.paintComponent(g);
int centre = getWidth() / 2;
g.drawLine(30, Y, Y , Y);
g.setColor(Color.ORANGE);
g.fillOval(centre, Y, diameter, diameter);
g.setColor(Color.BLACK);
g.drawOval(centre, Y, diameter, diameter);
g.drawOval(centre, Y, diameter / 2, diameter);
}
// on action performed...
public void actionPerformed(ActionEvent e) {
findDiameter();
repaint();
}
}
The problem is with your "Y" in CirclesPanel. Elements are drawn but outside the frame, try reducing Y, than surely you'll see your elements.
Alternatively increase the frame size.
I'm trying to learn drawing with swing. I'm trying to create a circle and position it on a specific position in a JPanel. This is what I've come up with but it does not show any figure:
import java.awt.*;
import javax.swing.*;
public class Circles extends JPanel {
private static final long serialVersionUID = 1L;
public Circles(){
setBackground(Color.white);
setPreferredSize(new Dimension(300, 300));
}
public void paintComponent(Graphics g){
super.paintComponents(g);
g.setColor(Color.black);
g.drawRect(10, 10, 50, 50);
}
}
This is the class that starts the program.
import java.awt.*;
import javax.swing.*;
public class StartCircles extends JFrame{
private static final long serialVersionUID = 1L;
private Circles circle;
public StartCircles(){
Container c = getContentPane();
circle = new Circles();
c.setBackground(Color.white);
c.setLayout(new FlowLayout());
setSize(300, 300);
c.add(circle);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args){
StartCircles c1 = new StartCircles();
}
}
What am I doing wrong? How do I position the figure where I want?
Try this SSCCE - noting the comments in the source.
import java.awt.*;
import javax.swing.*;
public class StartCircles extends JFrame{
private static final long serialVersionUID = 1L;
private Circles circle;
public StartCircles(){
Container c = getContentPane();
circle = new Circles();
c.setBackground(Color.white);
c.setLayout(new FlowLayout());
//setSize(300, 300);
c.add(circle);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack(); // size the GUI to the components within it
}
public static void main(String[] args){
StartCircles c1 = new StartCircles();
}
}
class Circles extends JPanel {
private static final long serialVersionUID = 1L;
public Circles(){
setBackground(Color.white);
setPreferredSize(new Dimension(300, 300));
}
public void paintComponent(Graphics g){
//super.paintComponents(g); // WRONG METHOD!
super.paintComponent(g);
g.setColor(Color.black);
g.drawRect(10, 10, 50, 50);
}
}
Your code running perfectly, but you are drawing Rectangle here.
so if you want to draw circle, you have to use
one of below methods
g.fillOval(10, 10, 50, 50);
g.drawOval(10, 10, 50, 50);
g.drawRect(10, 10, 50, 50); is sure to get you a rectangle. You need to look at the documentation for how to draw a circle.
You need to draw it using drawOval(). It takes 4 parameters:
x - the x coordinate of the upper left corner of the oval to be drawn.
y - the y coordinate of the upper left corner of the oval to be drawn.
width - the width of the oval to be drawn.
height - the height of the oval to be drawn.
So, replace your drawRect() with drawOval()
I want to set up a mathematical (where y grows up not down) coordinate space from (-1, -1) to (+1, +1) and have it fit in the window regardless of the window size.
I am using an anonymous JComponent subclass in Java SE 7 and casting the incoming Graphics in paintComponent to Graphics2D and then drawing on the Graphics2D
But the Graphics2D is set to a computer coordinate space that changes with the size of the window. How to get it to rescale according to window size and have Y go upwards? The following program should show a dark square in upper right quadrant.
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class G {
public static void main (String [] args) {
JFrame frame = new JFrame(G.class.getCanonicalName());
frame.setUndecorated(true);
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
paint2D((Graphics2D)g);
}
protected void paint2D (Graphics2D g2) {
g2.draw(new Rectangle2D.Double(0.1, 0.1, 0.9, 0.9));
}
};
frame.add(component);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
}
Setup the coordinate system how you want, using transform() and translate(). So:
you want the origin to be at (0, height); bottom left.
then you want to flip the Y axis.
Example code:
AffineTransform tform = AffineTransform.getTranslateInstance( 0, height);
tform.scale( 1, -1);
g2.setTransform( tform);
[My edited version]:
public static void main (String [] args) {
JFrame frame = new JFrame( G2dTransform_Question.class.getCanonicalName());
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
paint2D((Graphics2D)g);
}
protected void paint2D (Graphics2D g2) {
AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
tform.scale( getWidth(), -getHeight()); // NOTE -- to make 1.0 'full width'.
g2.setTransform( tform);
g2.setColor( Color.BLUE); // NOTE -- so we can *see* something.
g2.fill( new Rectangle2D.Double(0.1, 0.1, 0.8, 0.8)); // NOTE -- 'fill' works better than 'draw'.
}
};
frame.setLayout( new BorderLayout()); // NOTE -- make the component size to frame.
frame.add( component, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 400);
frame.setVisible(true);
}
[Hovercraft's version]: Thanks Hover!
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import javax.swing.JComponent;
import javax.swing.JFrame;
public class G {
public static final int PREF_W = 400;
public static final int PREF_H = PREF_W;
public static void main (String [] args) {
JFrame frame = new JFrame(G.class.getCanonicalName());
frame.setUndecorated(true);
JComponent component = new JComponent() {
private static final long serialVersionUID = 1L;
#Override
protected void paintComponent (Graphics g) {
super.paintComponent(g);
AffineTransform tform = AffineTransform.getTranslateInstance( 0, getHeight());
tform.scale( 1, -1);
Graphics2D g2 = (Graphics2D) g.create();
g2.setTransform( tform);
paint2D(g2);
g2.dispose();
}
protected void paint2D (Graphics2D g2) {
g2.draw(new Rectangle2D.Double(10, 10, 20, 30));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
};
frame.add(component);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
Right now I am making my jinternal frames transparent using this code:
double rgbConversionBackpack = Double.parseDouble(MyClient.configFile.getProperty("BACKPACK_FRAME_ALPHA"));
double tmp = (rgbConversionBackpack / 100.0) * 255.0;
this.getContentPane().setBackground(new Color(140, 0, 0, (int)tmp));
this.setOpaque(false);
I have code on the sliders to set the alpha which all works perfectly and saves it to a properties file, yada, yada, yada. The question is how do I make the entire JInternal Frame transparent.
Right now I have only be able to set the content pane, and any other panels (etc) that are in the jinternal frames transparent, but I want to make the entire JinternalFrame(borders and all) transparent.
Screenshot below shows how on the backpack the red tinted are is partially transparent and looks decent, but still want the border to be transparent also.
Is there a way to override the draw super method for each of my classes the extend JInternalFrame to have it draw semi transparent(depending on value obviously)?
You could do this by changing the AlphaComposite that the JInternalFrame's paint method uses. You have to be careful though to repaint the containing top level window at the location of the transparent component lest you have funny side effects. For example:
import java.awt.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
#SuppressWarnings("serial")
public class TransparentInternalFrame extends JDesktopPane {
private static final Color COLOR_1 = Color.red;
private static final Color COLOR_2 = Color.blue;
private static final float PT_2 = 30f;
private static final int PREF_W = 800;
private static final int PREF_H = 500;
public TransparentInternalFrame() {
add(new MyInternalFrame("Foo", 50, 50, 300, 300, 0.2f));
add(new MyInternalFrame("Foo", 400, 100, 300, 300, 0.4f));
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(new GradientPaint(0, 0, COLOR_1, PT_2, PT_2, COLOR_2, true));
g2.fillRect(0, 0, getWidth(), getHeight());
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
TransparentInternalFrame mainPanel = new TransparentInternalFrame();
JFrame frame = new JFrame("TransparentInternalFrame");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MyInternalFrame extends JInternalFrame {
private AlphaComposite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f);
public MyInternalFrame(String title, int x, int y, int w, int h, final float alpha) {
super(title);
setClosable(true);
setBounds(x, y, w, h);
setVisible(true);
int sliderValue = (int) (alpha * 100);
comp = comp.derive(alpha);
final JSlider slider = new JSlider(0, 100, sliderValue);
slider.setMajorTickSpacing(20);
slider.setMinorTickSpacing(5);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setBorder(BorderFactory.createTitledBorder("Alpha Value"));
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent cEvt) {
float alpha = (float) slider.getValue() / 100f;
setAlpha(alpha);
MyInternalFrame.this.repaint();
Window win = SwingUtilities.getWindowAncestor(MyInternalFrame.this);
win.repaint();
}
});
add(new JLabel("My Label", SwingConstants.CENTER));
add(slider, BorderLayout.SOUTH);
}
#Override
public void paint(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(comp);
super.paint(g);
}
public void setAlpha(float alpha) {
comp = comp.derive(alpha);
}
}
But note that this program is not fully fixed. You'll still see pixel errors if you drag one JInternalFrame over another. I still need to work the bugs out...
I am writing an application which has a JLayeredPane (call it layers) containing two JPanels in different layers. I override the paintComponent method of the JPanel at the bottom (call it grid_panel) so it paints a grid, and the the paintComponent method of the one at the top (call it circuit_panel) so it paints a circuit.
Here's a summary of the structure:
layers -
|-circuit_panel (on top)
|-grid_panel (at bottom)
I want the grid_panel to stay static, ie, not to do any repaint (except the initial one) since it does not change.
The trouble is, whenever I call circuit_panel.repaint(), grid_panel 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 written a small demo program:
public class Test2 extends JFrame {
public Test2() {
JLayeredPane layers = new JLayeredPane();
layers.setPreferredSize(new Dimension(600, 400));
MyPanel1 myPanel1 = new MyPanel1();
MyPanel2 myPanel2 = new MyPanel2();
myPanel1.setSize(600, 400);
myPanel2.setSize(600, 400);
myPanel1.setOpaque(false);
myPanel2.setOpaque(false);
myPanel2.addMouseListener(new MyMouseListener(myPanel2));
layers.add(myPanel1, new Integer(100)); // At bottom
layers.add(myPanel2, new Integer(101)); // On top
this.getContentPane().add(layers, BorderLayout.CENTER);
this.setSize(600, 400);
}
class MyPanel1 extends JPanel {
Color getRandomColor() {
int r = (int) (256 * Math.random());
int g = (int) (256 * Math.random());
int b = (int) (256 * Math.random());
return new Color(r, g, b);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getRandomColor());
g2d.fillRoundRect(30, 30, 60, 60, 5, 5);
}
}
class MyPanel2 extends JPanel {
Color getRandomColor() {
int r = (int) (256 * Math.random());
int g = (int) (256 * Math.random());
int b = (int) (256 * Math.random());
return new Color(r, g, b);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(getRandomColor());
g2d.fillRoundRect(45, 45, 75, 75, 5, 5);
}
}
class MyMouseListener extends MouseAdapter {
JPanel panel;
MyMouseListener(JPanel panel) {
this.panel = panel;
}
#Override
public void mouseClicked(MouseEvent e) {
panel.repaint();
}
}
/**
* #param args
*/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
(new Test2()).setVisible(true);
}
});
}
}
As you found, a BufferedImage is an effective way to cache complex content for efficient rendering; CellTest is an example. A flyweight renderer, shown here, is another approach. Finally, I've re-factored your instructive example in a way that may make experimentation easier.
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);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(color);
g2d.fillRoundRect(0, 0, getWidth(), getHeight(), 16, 16);
g2d.setColor(Color.black);
g2d.drawString(String.valueOf(n), 5, getHeight() - 5);
}
private void update() {
color = new Color(r.nextInt());
repaint();
}
}
private static class MouseHandler extends MouseAdapter {
LayerPanel panel;
MouseHandler(LayerPanel panel) {
this.panel = panel;
}
#Override
public void mouseClicked(MouseEvent e) {
panel.update();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
(new LayerDemo()).setVisible(true);
}
});
}
}