问题
Good day,
Hopefully this is a quick kill question. I am writing an application that uses JPanels and JLayeredPane inside a JFrame. On the initial start of my application, one of the panels does not show up until my mouse moves over the area where the panel should be. I even call the validate and repaint methods, but I am still able to display both panels together. Any suggestions? Thank you.
Here is my JFrame class (which has the main method)
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Application extends JFrame
{
public Application()
{
this.setSize(500,500);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
JLayeredPane lp = new JLayeredPane();
lp.setBounds(0,0,500,500);
this.setLayeredPane(lp);
Mypanel p1 = new Mypanel();
Mypanel2 p2 = new Mypanel2();
this.getLayeredPane().add(p1,0);
this.getLayeredPane().add(p2,1);
this.validate();
this.repaint();
this.validate();
}
public static void main(String[] args)
{
Application app = new Application();
}
}
Here is one of my panel classes
import javax.swing.JButton;
import javax.swing.JPanel;
public class Mypanel extends JPanel
{
public JButton button;
public Mypanel()
{
this.setLayout(null);
this.setBounds(0, 0, 500, 500);
JButton b = new JButton("Hello");
b.setBounds(20,20,300,300);
this.add(b);
}
}
And finally my last panel class
import javax.swing.JButton;
import javax.swing.JPanel;
public class Mypanel2 extends JPanel
{
public JButton button;
public Mypanel2()
{
this.setLayout(null);
this.setBounds(0, 0, 500, 500);
JButton b = new JButton("SUP");
b.setBounds(20,10,200,200);
this.add(b);
this.repaint();
this.validate();
this.repaint();
}
}
回答1:
First off, in a valid program only JComponent
repaints itself. If at some point you find that calling c.repaint()
from your controller code fixes some problem, you have neglected basic contracts that at the core of swing framework. And this is never a good idea. So removing all those repaint
and validate
calls is a good start. Next important thing is understanding how lightweight swing components go about painting their children. There are 2 modes: optimized and not optimized. The first one is only applicable when siblings don't overlap eachother in the container. If they do and optimized painting is on, you are going to get all sorts of weird behavior when those components repaint themselves(like when you hover mouse pointer over them). All lightweight components can handle overlapping children through setComponentZOrder()
. JLayeredPane only introduces the concept of a layer as a means of controlling zorder in a more flexible way. It tries to be smart about what mode to choose to paint its children but, sadly there are subtleties to how this works. so this code would do what you need:
Mypanel p1 = new Mypanel();
Mypanel2 p2 = new Mypanel2();
getLayeredPane().setLayer(p1,0);
getLayeredPane().setLayer(p2,1);
getLayeredPane().add(p1);
getLayeredPane().add(p2);
and this wouldn't:
Mypanel p1 = new Mypanel();
Mypanel2 p2 = new Mypanel2();
getLayeredPane().add(p1);
getLayeredPane().add(p2);
getLayeredPane().setLayer(p1,0);
getLayeredPane().setLayer(p2,1);
the trick is to call setLayer
before you add children to the container so that JLayeredPane would turn off optimized painting.
BTW I couldn't help but wonder why JLayeredPane
? If you need switching programmatically between different layouts maybe JTabbedPane is your answer anyways
回答2:
JLayeredPane lp = new JLayeredPane();
JPanel d = new JPanel();
d.setVisible(true);
d.setBounds(10, 10, 556, 386);
lp.add(d, new Integer(0), 0);
来源:https://stackoverflow.com/questions/11196587/jlayeredpane-not-drawing