Java编程思想中的一道练习题。我试着在Runnable接口的run()方法中调用repaint(),在paintComponent()方法中动态改变y坐标值,来实现动画。但是,运行时窗口时会不断重复绘制N多条正弦波,为什么repaint()不能清除之前绘制的图形再重新绘制呢?代码如下:
/************************************************************************
 * Java编程思想 第4版
 * 第22章 图形化用户界面
 * 练习25:(8)在SineWave.java的基础上编写程序(一个使用SwingConsole类的应用程序),
 * 在观察窗口画一条动态正弦波,它可以像示波器那样向后滚动,(使用一个线程来控制动画。动
 * 画的速度由java.swing.JSlider控件进行控制。)
 ************************************************************************/
 
package gui;
 
import java.awt.*;
import javax.swing.*;
//import javax.swing.event.*;
import static util.SwingConsole.*;//  util\SwingConsole.java是个JFrame框架。
 
class SwingDraw extends JPanel implements Runnable{
    final int POINT_NUM_PER_ONE_CYCLE = 200;
    int points;
    double[] sines;
    int[] pts;
    private int dy;
    protected int dv;
    private Thread animator;
 
    public void init (){}
 
    public void start (){
        if (animator == null){
            animator = new Thread( this );
            animator.start();
        }
    }
 
    public void run(){
        while ( Thread.currentThread() == animator ){
            repaint();
        }
    }
 
    public void stop(){
        animator = null;
    }
 
    @Override
    public void paintComponent (Graphics g){
        dy+=1;//通过dy增值,改变y坐标值,实现动态正弦波。
        points = POINT_NUM_PER_ONE_CYCLE*2;
        sines = new double[points];
        for(int i = 0;i<points;i++){
            double radians = (Math.PI/POINT_NUM_PER_ONE_CYCLE)*i+dy;
            sines[i] = Math.sin(radians);
        }
        int maxWidth = getWidth();
        double hstep = (double)maxWidth/(double)points;
        int maxHeight = getHeight();
        pts = new int[points];
        for(int i = 0;i<points;i++){
            pts[i]=(int)(sines[i]*maxHeight/2*.95+maxHeight/2);
        }
        g.setColor(Color.RED);
        for(int i = 1;i<points;i++){
            int x1 = (int)((i-1)*hstep);
            int x2 = (int)(i*hstep);
            int y1 = pts[i-1];
            int y2 = pts[i];
            g.drawLine(x1, y1, x2, y2);
        }
    }
    
}
 
public class SwingWaveRun extends JFrame{
    private SwingDraw sd = new SwingDraw();
//    private JSlider sDV = new JSlider(1,100,5);
    public SwingWaveRun(){
        add(sd);
        sd.start();
//        sDV.addChangeListener(new ChangeListener(){
//            public void stateChanged(ChangeEvent e){
//                 sd.dv=((int)((((JSlider)e.getSource()).getValue())/100));
//                 sd.repaint();
//            }
//        });
//        add(BorderLayout.NORTH,sDV);
    }
 
    public static void main(String[] args) {
        run(new SwingWaveRun(),700,450);
    }
}

解决方案 »

  1.   

    在paintComponment方法开始调用super.paintComponment(g)清空Off-screen bitmap
      

  2.   


    多谢huntor!调试后,正弦波可动态显示。书上只提到“当覆盖paintComponent()方法的时候,必须先调用该方法的基类版本;然后才可以做想做的事情,......”。当时没多想原因,写代码时,也就漏了。现在,我又纠结在下一个问题里了---如何通过JSlider控件控制动画速度,呵呵。
      

  3.   

    在SwingDraw里添加一个改变动画速度的方法。然后在JSlider的事件监听器里调用这个方法。