以下是《java2实用教程(第三版)》(耿祥义,张跃平著)例子7.24的源码。说明: 
该例子通过扩展Button类自治一个竖状的按钮来模仿交通信号灯,通过重写update()方法,有选择地清除按钮上以前所绘制的内容。 但是在运行的时候,我发现当单击鼠标速度很快时,上一次所绘的内容将不会被清除,既同时显示两个颜色的交通灯。单击速度放慢后则不会出现这个问题。 
在同时显示两个交通灯的情况下,窗口失去焦点再获得焦点将变为一个交通灯。 请问这个现象是什么原因造成的?import java.awt.*; 
import java.awt.event.*; 
class MyButton extends Button implements ActionListener{ 
    int x=10,y=10,i=0; 
    Color color[]={Color.red,Color.yellow,Color.green}; 
    Color c=color[0]; 
    MyButton(){ 
        setSize(38,85); 
        setBackground(Color.cyan); 
        addActionListener(this); 
    } 
    public void paint(Graphics g){ 
        g.setColor©; 
        g.fillOval(x,y,20,20); 
    } 
    public void update(Graphics g){ 
        g.clearRect(x,y,20,20); 
        paint(g); 
    } 
    public void actionPerformed(ActionEvent e){ 
        i=(i+1)%3; 
        c=color[i]; 
        y=y+23; 
        if(y>56)y=10; 
        repaint(); 
    } 

class WindowCanvas extends Frame{ 
    WindowCanvas(){ 
        MyButton button=new MyButton(); 
        setLayout(null); 
        add(button); 
        button.setLocation(30,30); 
        setBounds(60,125,100,200); 
        setVisible(true); 
        validate(); 
    } 

public class Example7_24{ 
    public static void main(String args[]){ 
        new WindowCanvas(); 
    } 
}

解决方案 »

  1.   

    调用repaint()时.会自动调用update(),不用改写它也行的,你试一下把update()注释掉,看看如何
      

  2.   

    你把你的actionPerformed方法里的repaint();去掉看行不行
    我去掉了,就不会出现你点的很快的时候,显示两个灯的情况了
      

  3.   

    2楼说的对,repaint()会去调用update()的
      

  4.   

    回2楼、4楼:
    把update()注释掉效果是一样的
    repaint()会自动调用update()和是否改写update()也不矛盾,所以我觉得问题不是出在这里。回3楼:
    把actionPerformed方法里的repaint();去掉后,虽然是不会出现同时两个灯的现象,但是如果点击太快回没有反应,再次点击灯会连续变化两次。
      

  5.   

    repaint()好像只会自动调用paint吧,不会调用update的
      

  6.   

    回5楼:
    具体调用过程是:repaint()调用update(),update()默认执行清空以前所绘内容并调用paint()回6楼:
    没有。如果你有解决方法或是想法的话欢迎发上来讨论。
      

  7.   

    没有人有任何想法吗?我又试了一下,在代码中加了三行,如下:
    import java.awt.*;
    import java.awt.event.*;
    class MyButton extends Button implements ActionListener{
    int x=10,y=10,i=0;
    Color color[]={Color.red,Color.yellow,Color.green};
    Color c=color[0];
    MyButton(){
    setSize(38,85);
    setBackground(Color.cyan);
    addActionListener(this);
    }
    public void paint(Graphics g){
    g.setColor(c);
    g.fillOval(x,y,20,20);
    }
    public void update(Graphics g){
    System.out.println("执行update()");//new
    g.clearRect(x,y,20,20);
    System.out.println("执行清除结束");//new
    paint(g);
    System.out.println("执行重绘结束");//new
    }
    public void actionPerformed(ActionEvent e){
    i=(i+1)%3;
    c=color[i];
    y=y+23;
    if(y>56)y=10;
    repaint();
    }
    }
    class WindowCanvas extends Frame{
    WindowCanvas(){
    MyButton button=new MyButton();
    setLayout(null);
    add(button);
    button.setLocation(30,30);
    setBounds(60,125,100,200);
    setVisible(true);
    validate();
    }
    }
    public class Example7_24{
    public static void main(String args[]){
    new WindowCanvas();
    }
    }每一次单击这三句都会打印,也就是说清除和重绘都是执行了的。可是同时显示两个灯的问题依然存在。
    我实在是没辙了。
      

  8.   

    http://168899.0033.cn
      

  9.   

    用双缓冲就行了.....
    改下update就好使了...import   java.awt.*;   
    import   java.awt.event.*;   
    class   MyButton   extends   Button   implements   ActionListener{   
            int   x=10,y=10,i=0;   
            Color   color[]={Color.red,Color.yellow,Color.green};   
            Color   c=color[0]; 
            Image image;
            MyButton(){   
                    setSize(38,85);   
                    setBackground(Color.cyan);   
                    addActionListener(this);   
            }   
            public   void   paint(Graphics   g){   
                    g.setColor(c);   
                    g.fillOval(x,y,20,20);   
            }   
            public   void   update(Graphics   g){   
              image = this.createImage(1024, 768);
         if (image != null) {
         Graphics g2 = image.getGraphics();
         paint(g2);
         g2.dispose();
         g.drawImage(image, 0, 0, null);
         } else {
         paint(g);
         }
                    paint(g);   
            }   
            public   void   actionPerformed(ActionEvent   e){   
                    i=(i+1)%3;   
                    c=color[i];   
                    y=y+23;   
                    if(y> 56)y=10;   
                    repaint();   
            }   
    }   
    class   WindowCanvas   extends   Frame{   
            WindowCanvas(){   
                    MyButton   button=new   MyButton();   
                    setLayout(null);   
                    add(button);   
                    button.setLocation(30,30);   
                    setBounds(60,125,100,200);   
                    setVisible(true);   
                    validate();   
            }   
    }   
    public   class   Example7_24{   
            public   static   void   main(String   args[]){   
                    new   WindowCanvas();   
            }   
    }
      

  10.   

    你的程序问题在于:
    g.clearRect(x,y,20,20);
    语句清除的是一个长宽都为20的矩型,它只能覆盖一个交通灯大小的区域,而当你快速单击的时候,实际上相当于两次执行了actionPerforemd方法,而执行的清除操作只对当前交通灯有效,对更前一次的时候是无效的,所以,第一次单击时的交通灯就没有被清除.如果你把清除操作修改成覆盖三个交通灯的矩形,例如
    g.clearRect(x,y,80,80);
    就不会出这个问题了
      

  11.   

    主要原因是:
    因为两次单击相隔时间太短,当你第一次单击的update还未调用时,第二次单击已经发生,此时坐标(x,y)已经变成了第二次第二次时的值,所以,起不到清除第一次时交通灯的作用.
      

  12.   

    这个主要是刷新的问题..
    SWING的刷新问题都是双缓冲来解决的..