问题
I subclass JPanel to overwrite paintComponent(Graphics), I want to draw an image onto jpanel in a jframe.
But my image hasn't shown up until I make a change to jframe's size. This is my code:
public class ImagePanel extends JPanel{
public void setImage(BufferedImage bi)
{
image = bi;
revalidate();
}
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
{
g.drawImage(image, 0, 0, this);
}
}
}
回答1:
Verify that you invoke setVisible()
after adding components and calling pack(), as discussed in this related example. You may also need to adopt an appropriate layout. Invoking repaint()
, as suggested here, may fix the symptom but not the underlying cause.
回答2:
If you want to "refresh" the JPanel then you should call repaint(), which will call your paintComponent(). This should fix your problem:
public void setImage(BufferedImage bi)
{
image = bi;
EventQueue.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});
}
Its good practice to update and change the GUI using the EDT. Heres more info on the EDT if you're interested:
How does the event dispatch thread work?
repaint
doesn't need to be called from the EDT. If you're changing the GUI, such as setting text to a JLabel, it should be inside of the EDT. Heres more information on what can be called outside of the EDT (courtesy of nIcE cOw):
Safe to use Component.repaint() outside EDT?
回答3:
Take a look at the docs for JPanel.add()
, which it inherits from java.awt.Container
:
Appends the specified component to the end of this container. This is a convenience method for addImpl(java.awt.Component, java.lang.Object, int). This method changes layout-related information, and therefore, invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component.
Emphasis added.
Therefore, if you modify a Container after it's already been displayed, you must call validate()
in order for it to show up. Just invoking repaint()
is not enough. You may have noticed that calling setVisible(true)
also works; this is because it calls validate() internally.
回答4:
I had the same problem and fixed it by call setVisible(true); the JFrame I was using.
Example : if your JFrame does not update after using :
jframe.setContentPane(new MyContentPane());
fix it with :
jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);
I know that it sounds silly to do this even though your JFrame is already visible, but that's the only way I've found so far to fix this problem (the solution proposed above didn't work for me).
Here is a complete example. Run it and then uncomment the "f.setVisible(true);" instructions in classes Panel1 and Panel2 and you'll see the difference. Don't forget the imports (Ctrl + Shift + O for automatic imports).
Main class :
public class Main {
private static JFrame f;
public static void main(String[] args) {
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Panel1(f));
f.pack();
f.setVisible(true);
}
}
Panel1 class :
public class Panel1 extends JPanel{
private JFrame f;
public Panel1(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 1");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel2(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Panel2 class :
public class Panel2 extends JPanel{
private JFrame f;
public Panel2(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 2");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel1(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Hope that helps.
Regards.
回答5:
I also had same problem but I found a solution. Just create a jframe
object on top and call jframe
methods at the bottom like jf.pack()
, jf.setVisible()
, jf.setSize()
, jf.setDefaultCloseOpetion()
should be at the bottom of the all UIs added in that frame you will find it work great.
来源:https://stackoverflow.com/questions/11069807/jpanel-doesnt-update-until-resize-jframe