I have a very basic little JFrame with JToggleButtons and subclassed JPanels that know how to draw what I want them to draw. Selecting a button causes an oval to appear in the corresponding panel. Unselecting the buttons makes the drawings disappear.
Unfortunately, minimizing (iconifying) and then restoring (deiconifying) causes any drawn shapes to disappear. So I need to trigger redrawings manually. The problem is that I can only get the redrawing done (that is, I only see it) if I show a message box first.
Here's the deiconify event for the JFrame:
private void formWindowDeiconified(java.awt.event.WindowEvent evt)
{
//having this message makes everything work
JOptionPane.showMessageDialog(null, "Useless message this is.");
//but if I skip it, I'm SOL
//what's going on?
drawAll();
}
This method goes over all of my buttons and asks for the redraws when necessary:
public void drawAll()
{
for (int i=0; i<channels; i++)
{
if (buttons[i].isSelected())
{
lightboxes[i].drawMe();
}
}
}
and here is my subclassed JPanel:
class MyJPanel extends JPanel {
public void drawMe()
{
Graphics myGraphics = this.getGraphics();
myGraphics.fillOval(0, 0, this.getWidth(), this.getHeight());
}
public void unDraw()
{
this.invalidate();
this.repaint();
}
}
Firstly, for speed I would use double buffering. It's best to paint your graphics off screen and display them to the screen when the drawing has completed. The below should sort you out.
The window should automatically be repainted once it is restored by the
RepaintManager
. The problem is you are not performing custom painting like you should...This is not how to do custom painting...
getGraphics
can returnnull
and is, at best, a snapshot of the graphics state.Painting in Swing can occur at any time for many different reasons, most of which you don't have control over (nor should you care).
Your job is simply to respond to these repaint requests and update your components state.
Swing has a detailed paint chain which is called automatically and which you can use.
You should be overriding
paintComponent
and performing all painting within this methodTake a look at Performing Custom Painting and Painting in AWT and Swing for more details
I'm just providing this answer so people can see what I ended up doing. The major lesson pointed out by everyone was to use the component's paintComponent. See the comments for issues that you might be experiencing yourself.
Edit: Updated to reflect comments from MadProgrammer.
I subclassed the buttons too, so I can get its "ID" off of it from the event handler:
The JFrame code that makes the buttons:
And that's the only manual redrawing I have to do - resizing and reshowing and all those other fun things eventually hit up the paintComponent, and it just has to know if its button is pushed to know what to do. Super clean and just what I wanted.