I am a new learner of Java Swing. I am trying to draw some shapes.
But when I run the following codes, I can't see the graph at all.
Can't understanding why, Could someone help me with it? Thanks a lot!
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Draw
{
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
DrawFrame frame = new DrawFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
class DrawFrame extends JFrame
{
public static final int DEFAULT_WIDTH = 400;
public static final int DEFAULT_HEIGHT = 400;
public DrawFrame()
{
setTitle("DrawTest");
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
DrawComponent component = new DrawComponent();
add(component);
}
}
class DrawComponent extends JComponent
{
public void painComponent(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
Rectangle2D rec = new Rectangle2D.Double(100, 100, 200, 150);
g2.draw(rec);
Ellipse2D ellipse = new Ellipse2D.Double();
ellipse.setFrame(rec);
g2.draw(ellipse);
}
}
In the supplied code, the paintComponent method has an error in the name:
public void painComponent(Graphics g)
So it's not actually overriding the method from the superclass. You can add the #Override annotation so that the compiler will give an error if the method doesn't actually override anything, for example:
#Override
public void painComponent(Graphics g)
Related
I am making a game by java and it refreshes itself 60 times per second. Every time it executes a loop and I use g2d to draw images and strings. Things work fine if I do g2d.setFont(new Font("Arial", Font.PLAIN, 8)); and drawstring and it would be normal, but if I set the font to some "unfamiliar" fonts and do the same thing, the swing would show white screen in the first second of start up then paint everything correctly and it's apparently too slow (2 secs).
I put a jpanel in a jframe and override the paint() method of jpanel to draw everything I need. I've already used SwingUtilities.invokeLater in my code.
import javax.swing.*;
import java.awt.*;
public class Window extends JFrame{
public Window(){
add(new Board());
setSize(800,600);
setVisible(true);
}
public static void main(String[] args){
new Window();
}
private class Board extends JPanel {
Font font = new Font("Bitmap", Font.PLAIN, 64);
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setFont(font);
g2d.drawString("This is slow", 220,200);
Toolkit.getDefaultToolkit().sync();
g2d.dispose();
g.dispose();
}
}
}
This is not in a loop but it's very laggy.
http://fontsov.com/download-fonts/bitmap1159.html
This is the cutie font that slows our application down. "Arial" will load blazingly fast. How can I make this less laggy?
First and foremost, for best help, create and post your minimal code example program for us to review, test, and possibly fix. Without this, it will be hard for us to fully understand your problem.
Consider:
Overriding paintComponent not paint to get the advantage of double buffering.
Avoid using invokeLater unless you're sure that the code is being called off of the Swing event thread and you are making calls that need to be on the event thread.
Put slow running code in a background thread such as that which can be found using a SwingWorker.
Putting your text in a JLabel, not drawn on a component.
Draw all static images to a BufferedImage, and displaying that in paintComponent. Then draw all changing images, such as your moving sprites, directly in the paintComponent method.
Don't forget to call your super.paintCompmonent(g) within your paintComponent(Graphics g) method override.
Edit
A BufferedImage solution could look like,....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
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();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); //do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
paintGame(g2d);
// Toolkit.getDefaultToolkit().sync();
// g2d.dispose();
// g.dispose();
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
mainImage = new BufferedImage(PREF_W, PREF_H, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = mainImage.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
}
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
Edit 2
Or with a SwingWorker background thread....
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
public class FooFun {
private static void createAndShowGui() {
ChildClass mainPanel = new ChildClass();
JFrame frame = new JFrame("FooFun");
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();
}
});
}
}
abstract class FirstClass extends JPanel {
private static final int FPS = 20;
public FirstClass() {
new Timer(1000 / FPS, taskPerformer).start();
}
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLoop(); // do loop here
repaint();
}
};
private void gameLoop() {
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
paintGame(g2d);
}
public abstract void paintGame(Graphics2D g2d);
}
class ChildClass extends FirstClass {
private static final Font font = new Font("Bitmap", Font.PLAIN, 64);
private static final int PREF_W = 900;
private static final int PREF_H = 600;
private static final String NIGHT_IN_VEGAS_TEXT = "a Night in Vegas";
private static final int NIV_X = 240;
private static final int NIV_Y = 130;
private BufferedImage mainImage;
public ChildClass() {
imgWorker.addPropertyChangeListener(new ImgWorkerListener());
imgWorker.execute();
}
private class ImgWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
try {
mainImage = imgWorker.get();
// repaint() here if you don't have a game loop running
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
SwingWorker<BufferedImage, Void> imgWorker = new SwingWorker<BufferedImage, Void>() {
#Override
protected BufferedImage doInBackground() throws Exception {
BufferedImage img = new BufferedImage(PREF_W, PREF_H,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.setFont(font);
g2.setColor(Color.black);
g2.drawString(NIGHT_IN_VEGAS_TEXT, NIV_X, NIV_Y);
g2.dispose();
return img;
}
};
#Override
public void paintGame(Graphics2D g2d) {
if (mainImage != null) {
g2d.drawImage(mainImage, 0, 0, this);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
it's a bit uneconomic to create a new Font each time paint() is called (which happens a lot), you could move that to your constructor.
and the font should be changed to some orthodox fonts (Arial,Calibri etc)
This code is supposed to be simple java game.There's one green moveable rectangle (player) and few other rectangles (enemies).I've set up key listener for frame, so green rectangle can be moveable.But to make change of player's x and y coords noticeable, I have to call repaint in paintCoponent method.When I do so I can move green rect but other rectangles are being generated over again on new coordinates.How to I stop this unwished effect?
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
public class Drawing extends JPanel implements KeyListener
{
public static JFrame frame;
public static int[] x=new int[10];
public static int[] y=new int[10];
public static int a;
public static Random random;
public static int p_x=0;
public static int p_y=0;
public static void drawframe(int width,int height)
{
frame=new JFrame("The game");
frame.setSize(width,height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(false);
frame.addKeyListener(new Drawing());
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
drawenemies(g,6);
setradius(g);
setplayer(g);
}
public void drawenemies(Graphics g,int amount)
{
random=new Random();
a=amount;
for(int i=1;i<=amount;i++)
{
x[i]=random.nextInt(frame.getWidth());
y[i]=random.nextInt(frame.getHeight());
g.fillRect(x[i], y[i], 20, 20);
}
}
public void setradius(Graphics g)
{
g.setColor(Color.RED);
for(int i=1;i<=a;i++)
{
g.drawRect(x[i]-15, y[i]-15, 50, 50);
}
}
public void setplayer(Graphics g)
{
g.setColor(Color.GREEN);
g.fillRect(p_x, p_y, 20, 20);
}
public static void main(String args[])
{
drawframe(500,500);
Drawing instance=new Drawing();
frame.add(instance);
}
#Override
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode()==39)
{
p_x=p_x+10;
}
}
public void keyReleased(KeyEvent arg0){}
public void keyTyped(KeyEvent arg0){}
}
The code does not exhibit the behavior you describe.
However, you have two separate instances of Drawing:
frame.addKeyListener(new Drawing());
//....
Drawing instance=new Drawing();
Remove the top one and use the one in main:
Drawing instance=new Drawing();
frame.add(instance);
frame.addKeyListener(instance);
Also, do not call repaint() in paintComponent(Graphics) as this will continuously generate paint calls. Call it after you make some modification to state - e.g. in keyPressed(KeyEvent).
See also Painting in AWT and Swing.
this is the documentacion:
Causes doRun.run() to be executed asynchronously on the AWT event
dispatching thread. This will happen after all pending AWT events have
been processed. This method should be used when an application thread
needs to update the GUI. In the following example the invokeLater call
queues the Runnable object doHelloWorld on the event dispatching
thread and then prints a message.
but i want to know how it means in code
I always made a program like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.image.BufferedImage;
/**
*
* #author Robin
*/
public class Example {
JFrame Frame=new JFrame();
public Example() {
Frame.setTitle("Example");
Frame.setName("Example");
Frame.setSize(300, 300);
Frame.setResizable(false);
Frame.setUndecorated(false);
Frame.setLayout(null);
Frame.setLocationRelativeTo(null);
Frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Frame.setIconImage(CrearIcono(Color.decode("#F4141D")).getImage());
Frame.getContentPane().setBackground(Color.WHITE);
Formato();
Accion();
Mover(Frame.getGlassPane());
Frame.setVisible(true);
}
private void Formato() {
}
private void Accion() {
}
public ImageIcon Imagen( String dir){return new ImageIcon(getClass().getResource("/lib/"+dir));}
public static void Mover(final Component objeto) {
MouseInputAdapter d=new MouseInputAdapter() {int x,X,y,Y;
#Override public void mousePressed(MouseEvent e){x=e.getXOnScreen();X=objeto.getLocation().x;y=e.getYOnScreen();Y=objeto.getLocation().y;}
#Override public void mouseDragged(MouseEvent e){objeto.setLocation(X+(e.getXOnScreen()-x), Y+(e.getYOnScreen()-y));}};
objeto.addMouseListener(d);objeto.addMouseMotionListener(d);
}
public int CentrarX(int AnchoObjeto, int AnchoRespectoA){return (AnchoRespectoA/2)-(AnchoObjeto/2);}
public int CentrarY(int LargoObjeto, int LargoRespectoA){return (LargoRespectoA/2)-(LargoObjeto/2);}
public int ImgA(JLabel imagen){return imagen.getIcon().getIconWidth();}
public int ImgL(JLabel imagen){return imagen.getIcon().getIconHeight();}
public static ImageIcon CrearIcono(Color color) {
int WIDTH = 32;
int HEIGHT = 32;
BufferedImage img = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
int[] xPoints = {WIDTH, 0, 0, WIDTH / 2};
int[] yPoints = {0, WIDTH / 2, WIDTH, WIDTH};
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setColor(color);
g2.fillPolygon(xPoints, yPoints, xPoints.length);
g2.dispose();
ImageIcon icon = new ImageIcon(img);
return icon;
}
public static void main(String[] args) {
Example Ventana=new Example();
}
}
what is better? what is the difference?
SwingUtilities.invokeLater
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
pantalla principal=new pantalla();
Calendario s=new Calendario(1);
}
});
}
Without invokeLater
public static void main(String[] args) {
Example Ventana=new Example();
}
thanks for your advices
The first one using invokeLater(..) is better in that it is the correct way to create a GUI.
See Concurrency in Swing (and particularly 'Initial Threads') for more details.
I'm trying to draw two lines in a Canvas in Java, calling two methods separately, but when I draw the second line, the first one disapears (Java clears the screen). How can I avoid that? I want to see the two lines. I've seen paint tutorials (how to make a program like the Paint on Windows) where the user uses the mouse to draw lines and when one line is drawn, the other do not disappear. They just call the paint method and it does not clear the screen.
I'll be grateful if anyone can help me.
Thanks.
View Class
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class CircuitTracePlotView extends JFrame {
private CircuitTracePlot circuitTracePlot;
public CircuitTracePlotView() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.getContentPane().add(circuitTracePlot = new CircuitTracePlot(), BorderLayout.CENTER);
this.pack();
this.setSize(250,250);
this.setLocationRelativeTo(null);
this.setVisible(true);
circuitTracePlot.drawLine();
circuitTracePlot.drawOval();
}
}
class CircuitTracePlot extends Canvas {
private final static short LINE = 1;
private final static short OVAL = 2;
private int paintType;
private int x1;
private int y1;
private int x2;
private int y2;
public CircuitTracePlot() {
this.setSize(250,250);
this.setBackground(Color.WHITE);
}
private void setPaintType(int paintType) {
this.paintType = paintType;
}
private int getPaintType() {
return this.paintType;
}
public void drawLine() {
this.setPaintType(LINE);
this.paint(this.getGraphics());
}
public void drawOval() {
this.setPaintType(OVAL);
this.paint(this.getGraphics());
}
public void repaint() {
this.update(this.getGraphics());
}
public void update(Graphics g) {
this.paint(g);
}
public void paint(Graphics g) {
switch (paintType) {
case LINE:
this.getGraphics().drawLine(10, 10, 30, 30);
case OVAL:
this.getGraphics().drawLine(10, 20, 30, 30);
}
}
}
Main class
import javax.swing.SwingUtilities;
import view.CircuitTracePlotView;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
CircuitTracePlotView cr = new CircuitTracePlotView();
}
});
}
}
You almost never should call paint(...) directly. I can count the times that I've needed to do this on one hand.
Do not get a Graphics object by calling getGraphics() on a component as that will return a non-durable Graphics object. Instead either draw in a BufferedImage and display that in the paint method or draw in the paint method (if AWT).
Since this is a Swing GUI, don't use an AWT component to draw in. Use a JPanel and override the paintComponent(...) method, not the paint(...) method. Otherwise you lose all benefits of Swing graphics including automatic double buffering.
The super.paintComponent(g) method should be called in the paintComponent(Graphics g) override, often as the first method call inside of this method. This lets the component do its own housekeeping painting, including erasing drawings that need to be erased.
Read the tutorials on Swing graphics as most of this is all well explained there. For e.g., please have a look here:
Lesson: Performing Custom Painting
Painting in AWT and Swing
Edit
To have your images persist, I suggest that you draw to a BufferedImage and then display that Image in your JPanel's paintComponent(...) method.
Or another option is to create a Collection of Shape objects, perhaps an ArrayList<Shape> and fill it with the Shapes you'd like to draw, and then in the paintComponent(...) method cast the Graphics object to a Graphics2D object and iterate through the Shape collection drawing each shape with g2d.draw(shape) as you iterate.
Since Trash posted his code,...
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class CircuitTracePlot2 extends JPanel {
private static final int PREF_W = 250;
private static final int PREF_H = PREF_W;
private int drawWidth = 160;
private int drawHeight = drawWidth;
private int drawX = 10;
private int drawY = 10;
private PaintType paintType = PaintType.LINE;
public CircuitTracePlot2() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
public void setPaintType(PaintType paintType) {
this.paintType = paintType;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (paintType == null) {
return;
}
switch (paintType) {
case LINE:
g.drawLine(drawX, drawY, drawWidth, drawHeight);
break;
case OVAL:
g.drawOval(drawX, drawY, drawWidth, drawHeight);
break;
case SQUARE:
g.drawRect(drawX, drawY, drawWidth, drawHeight);
default:
break;
}
}
private static void createAndShowGui() {
final CircuitTracePlot2 circuitTracePlot = new CircuitTracePlot2();
JFrame frame = new JFrame("CircuitTracePlot2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(circuitTracePlot);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
int timerDelay = 2 * 1000;
new Timer(timerDelay , new ActionListener() {
private int paintTypeIndex = 0;
#Override
public void actionPerformed(ActionEvent arg0) {
paintTypeIndex++;
paintTypeIndex %= PaintType.values().length;
circuitTracePlot.setPaintType(PaintType.values()[paintTypeIndex]);
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum PaintType {
LINE, OVAL, SQUARE;
}
Here's a variation on your program that implements much of #Hovercraft's helpful advice. Try commenting out the call to setPaintType() to see the effect.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/** #see http://stackoverflow.com/a/15854246/230513 */
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
CircuitTracePlotView cr = new CircuitTracePlotView();
}
});
}
private static class CircuitTracePlotView extends JFrame {
private CircuitTracePlot plot = new CircuitTracePlot();
public CircuitTracePlotView() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
plot.setPaintType(CircuitTracePlot.OVAL);
this.add(plot, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
private static class CircuitTracePlot extends JPanel {
public final static short LINE = 1;
public final static short OVAL = 2;
private int paintType;
public CircuitTracePlot() {
this.setBackground(Color.WHITE);
}
public void setPaintType(int paintType) {
this.paintType = paintType;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
switch (paintType) {
case LINE:
g.drawLine(10, 10, 30, 30);
case OVAL:
g.drawOval(10, 20, 30, 30);
default:
g.drawString("Huh?", 5, 16);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
}
Pretty much like the title says - I've got a JPanel, and I'd like to have it at 90% opacity if inactive, and full opacity if moused over.
I've got the separate components working - the mouse over and out is OK and I can change the opacity from overriding the paintComponent method, but I suppose I'm having trouble with the connection between the MouseAdapter and the paintComponent.
It seems there's probably a really easy way to do this - any tips?
(BTW sorry left the code at home so no example for now :( unless it's not quickly solvable then I'll throw some code up tomorrow.)
If you are overriding the paintComponent method, you should be able to add an opacity variable to the JPanel extension. Modify this in the MouseAdapter (using mutators). Then refer to this variable in the overridden paintComponent method to determine how to paint.
If you override the paintComponent method already, I'd suggest you make the MouseAdapter an anonymous inner class of your Panel and let it manipulate a private boolean flag.
public class FadingPanel extends JPanel
{
private boolean active;
public FadingPanel()
{
createMouseAdapter();
}
private void createMouseAdapter()
{
this.addMouseListener(new MouseAdapter()
{
// your mouseadapter code here toggling the active flag
}
}
#Override
public boolean paintComponent(Graphics g)
{
if(active)
{
super.paintComponent(g);
}
else
{
// your semitransparent painting code here
}
}
}
Shoot, I don't have the Haase and Guy book with me, and I don't remember the way they recommend to code for translucent components, but I guess overriding either paint or paintComponent work except that overriding paint will show the effect on child components from the get-go. For example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class OpaqueJPanels {
private static void createAndShowUI() {
JPanel mainPanel = new JPanel(new GridLayout(1, 0));
mainPanel.add(new OpaqueJPanel(false, "Override paintComponent"));
mainPanel.add(new OpaqueJPanel(true, "Override paint"));
JFrame frame = new JFrame("Opaque JPanels");
frame.getContentPane().add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
class OpaqueJPanel extends JPanel {
private static final int OJP_WIDTH = 250;
private static final int OJP_HEIGHT = OJP_WIDTH;
private static final Composite TRANSLUSCENT_COMPOSITE = AlphaComposite
.getInstance(AlphaComposite.SRC_OVER, 0.4f);
private static final Composite NON_TRANSLUSCENT_COMPOSITE = AlphaComposite
.getInstance(AlphaComposite.SRC_OVER, 1.0f);
private boolean overridePaint;
private boolean transluscent = true;
public OpaqueJPanel(boolean overridePaint, String title) {
add(new JButton("Button"));
setBorder(BorderFactory.createTitledBorder(title));
addMouseListener(new MouseAdapter() {
#Override
public void mouseEntered(MouseEvent e) {
transluscent = false;
getParent().repaint();
}
#Override
public void mouseExited(MouseEvent e) {
if (!OpaqueJPanel.this.contains(e.getPoint())) {
transluscent = true;
getParent().repaint();
}
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(OJP_WIDTH, OJP_HEIGHT);
}
#Override
public void paint(Graphics g) {
if (!overridePaint) {
super.paint(g);
return;
}
Graphics2D g2 = (Graphics2D) g;
Composite composite = transluscent ? TRANSLUSCENT_COMPOSITE
: NON_TRANSLUSCENT_COMPOSITE;
g2.setComposite(composite);
super.paint(g);
}
#Override
protected void paintComponent(Graphics g) {
if (overridePaint) {
super.paintComponent(g);
return;
}
Graphics2D g2 = (Graphics2D) g;
Composite composite = transluscent ? TRANSLUSCENT_COMPOSITE
: NON_TRANSLUSCENT_COMPOSITE;
g2.setComposite(composite);
super.paintComponent(g);
}
}
I also found that it was better if I repainted the JPanel's parent component rather than the JPanel itself.