才找到这个错误,不得不感慨:粗心才是程序员的噩梦啊!
马士兵曰过:“重写方法你给我在API文档中找方法签名!”,小许,你懂了吗?
不过小许问的问题倒让我发现了Swing中paint与paintComponent的区别。
查API文档,查得在类Jcomponent下的paint方法有以下解释: “This method actually delegates the work of painting to three protected methods:
paintComponent
, paintBorder
, and paintChildren
. They're called in the order listed to ensure that children appear on top of component itself.”也就是说当Swing中的paint方法被调用时,paintComponent、paintBorder、 paintChildren 这三个方法也会被按顺序调用,之所以要按这个顺序调用是为了保证子组件能正确地显示在目前这个组件之上。
所以paintComponent就是本身这个容器自己画出自己组件的方法了。如果只是为了改变本身这个容器中的组件,只需要改写paintComponent方法就可以了,如果还要保留容器中的原本组件就别忘了调用super.paintComponent(g)。如果要改写paint方法来改变本身这个容器的组件,那么也别忘了要调用super.paint(g),不然出来的东西是不包含原组件、原边框和子组件的。这个做个实验就可以很快验证的。
public class MyDrawPanel extends JPanel{
public void paint(Graphics g){
//super.paint(g);
g.setColor(Color.orange);
g.fillRect(20, 50, 100, 100);
}
public static void main(String[] args){
JFrame frame = new JFrame();
MyDrawPanel panel = new MyDrawPanel();
JLabel label = new JLabel("aaa");
panel.setBackground(Color.blue);
panel.add(label);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
以上这个程序除了JPanel本身正常显示之外还会显示出子组件label和一个方块。如果注释掉super.paint(g),那么就只能显示出方块了。
不过我还发现了一个更神奇的地方。那就是以上这些只适用于Swing,如果换成awt就不同了。
awt要改变组件样式,只能重写paint方法了,因为他是没有paintComponent方法的。什么?你有发现这个方法?!如果你看清楚你就会发现这个方法不是paintComponent而是paintComponents方法,后面多了一个s 这个paintComponents方法按API说是用来把所有的容器内组件都显示出来的方法,我做了一下实验,这个方法在容器对象初始化的时候应该是没有被自动调用的,当你要用的时候只能自己调用了,不过好像只是显示出子组件而已,因为awt中即使重写paint方法而没有调用父类的paint方法是不影响本身容器自己的组件显示的。这是一个例子:
public class MyDrawPanel extends Panel{
public void paint(Graphics g){
//super.paint(g);
g.setColor(Color.orange);
g.fillRect(20, 50, 100, 100);
paintComponents(g);
}
public static void main(String[] args){
JFrame frame = new JFrame();
MyDrawPanel panel = new MyDrawPanel();
JLabel label = new JLabel("aaa");
panel.setBackground(Color.blue);
panel.add(label);
frame.getContentPane().add(panel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
可以把paintComponents(g)注释掉再看看效果。 总结了一下:Swing中改变组件样式重写paintComponent就可以了,其他paintBorder和paintChildren默认就可以。awt中改变组件样式要重写paint方法,而且如果不需要调用super.paint(g)就可以保留原组件样式,但是不会显示子组件样式,可以调用paintComponents(g)解决这个问题。