回 帖 发 新 帖 刷新版面

主题:关于 paintComponent() 调用的问题

我遇到一个问题,有高手给解答一下,先说声谢谢.
程序如下:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class javademo extends JFrame{    
    public javademo(){
    Container con=this.getContentPane();
    con.setLayout(null);                
    paintpanel pp=new paintpanel(Color.red);
    con.add(pp);
    setSize(210,200);
    }    
    public static void main(String args[]){
        javademo jd=new javademo();
        jd.setVisible(true);
    }

}

class paintpanel extends JPanel{
   Color c;
   public paintpanel(Color color){
        c=color;
   }
   public void paintComponent(Graphics g){
       super.paintComponent(g);     //这一句到底有什么做用,我一直不知道.书上说,必须有
       g.setColor(c);
       g.fillRect(0,0,80,40);
   }


我希望绘图的位置固定,其他地方好放其他控件.但是无显示.请指教

回复列表 (共2个回复)

沙发

如果父类容器为空布局,则必须为子组件指定大小

con.setLayout(null);                
paintpanel pp=new paintpanel(Color.red);
pp.setBounds(0, 0, 202, 166); //必须指定面板的大小
con.add(pp);

板凳

初始问题:super.paintComponent到底做了什么,以至于子类覆盖时必须调用它?

不妨从源码里追溯一下
首先查看JPanel。其定义public class JPanel extend JComponent
找了一下,发现JPanel里没有paintComponent方法
继续找其父类,在JComponent里找到了paintComponent,其代码片段如下

protected void paintComponent(Graphics g) {
        if (ui != null) {
            Graphics scratchGraphics = SwingGraphics.createSwingGraphics(g);
            try {
                ui.update(scratchGraphics, this);
            }
            finally {
                scratchGraphics.dispose();
            }
        }
}

新的问题产生:
为什么要创建一个scratchGraphics?
ui.update更新了什么?
为什么要dispose一下?
我们逐个来解决。

首先,追踪createSwingGraphics方法
public static Graphics createSwingGraphics(Graphics g) {
        if (g == null) {
            Thread.dumpStack();
            return null;
        }
        return g.create();
}
发现只是简单的调用了一下Graphics接口的create方法,建立了一个新的图对象。

接着,看ui.update
public void update(Graphics g, JComponent c) {
    if (c.isOpaque()) {
        g.setColor(c.getBackground());
        g.fillRect(0, 0, c.getWidth(),c.getHeight());
    }
    paint(g, c);
}
利用上一步所创建的图对象,把组件的背景色画了出来。

最后一个dispose,查看Graphics接口的源码,根据Graphics对dispose方法的说明,此方法是丢弃Graphics,并释放其所占内存资源的。看来这句话的作用就是把用来画背景色的图对象抛弃了。


根据以上追踪,我们发现paintComponenet的作用是给组件画上背景色。
如果不调用此方法,我们之前对JPanel设置的背景色等属性将不会被展现。
而且根据源代码,我们发现涂背景时机也是有讲究的。

如果此方法在子类的实现中最先被调用,背景就处于最底下的一层,子类其他利用g进行的绘图将在有一个背景的基础下进行。
如果此方法没有最先被调用,在此方法前所做的绘图动作都会被画出来的背景overwrite。


结论:paintComponent方法应该要被所有子类调用,而且是在最先调用。

我来回复

您尚未登录,请登录后再回复。点此登录或注册