【Swing】paint与paintComponent的区别

关于paint()在什么时候被程序调用??

当java认为需要重新绘制组件的时候由java调用。
例如你在程序中repaint();或者程序窗口最小化,然后恢复。或者程序窗口被遮挡,又显现的时候。
你注意观察,这个方法是个受保护的方法,这就是说我们平常并不用管这个方法,这个方法只在你需要继承paintComponent(一般是JFrame)的时候,重写方法,(也可以不重新方法,如果你不需要改变绘制组件动作的话)。

下面我们看这个方法的源代码
public void paintComponents(Graphics g) {
        if (isShowing()) {
     GraphicsCallback.PaintAllCallback.getInstance().
         runComponents(component, g, GraphicsCallback.TWO_PASSES);
 }
    }
你会发现这个方法会调用一个Callback。而
private PaintCallback() {}
        public void run(Component comp, Graphics cg) {
            comp.paint(cg);
        }
我们发现这个callback 会调用comp.paint(cg);
也就是说调用paintComponent(),归根究底还是调用了我们写的,paint()方法。

super.paintComponent(g);的问题

简明回答一:

重写paintComponent方法时先调用父类的paintComponent()
简单点说,因为super.paintComponent()这一句是调用了父类的方法,那么,你每次重绘(repaint())的时候,程序就会调用到自身的paintComponent()方法,(它覆盖了父类的同名方法)而你在paintComponent方法中第一行就先调用了super.paintComponent进行界面重绘,那么就由父类先进行界面重绘。
如果注释掉super.paintComponent()的话,那么你的类本身已经覆盖掉它的父类的paintComponent方法,界面需要重绘的时候,纯粹是你定义的那个类的paintComponent方法中的代码负责重绘。

简明回答二:

首先,java里面的paint()方法不是由用户调用的,而是由虚拟机系统调用的,paintComponent()也是一样。 
其次、你要重写JPanel这个父类的paintComponent()方法,来实现自己的绘制方案。因为你的类是从JPanel继承而来的,相当于这个类本身就保存了JPanel的一个引用。当你重写paintComponent()方法时,为了确保在此期间,父类JPanel能把自己的paintComponent()方法运行完,就要调用super.paintComponent() 
然后再运行你自己的paintComponent(); 


否则就有可能出现的情况是,父类JPanel自己还没有绘制完,程序已经开始绘制子类的了。 

查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),不然出来的东西是不包含原组件、原边框和子组件的。这个做个实验就可以很快验证的。
         

package lzm;

import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MyDrawPanel extends JPanel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(Color.red);
		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.yellow);
		panel.add(label);
		frame.setContentPane(panel);
		//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方法是不影响本身容器自己的组件显示的。这是一个例子:
         
package lzm;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Panel;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class MyDrawPanel extends Panel {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void paint(Graphics g) {
		// super.paint(g);
		g.setColor(Color.red);
		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.orange);
		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)解决这个问题。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值