2013-04-30 64 views
0

对于作业分配,我必须制作一个程序,其中一个窗口以三个按钮打开:Drop,Retrieve和Quit。当按下按钮时,一个圆从显示面板的顶部落到底部并停留在那里。当按下“恢复”按钮时,一条线应该沿着屏幕落到圆圈上,然后将圆圈直接拉回到屏幕顶部。Java代码中的计时器问题

我已经写了几乎所有的东西,我只是无法让线返回到屏幕上,在我的代码中只有球和线保持在那里。

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

public class DisplayWindow extends JFrame { 
    private Container c; 

    public DisplayWindow() { 
     super("Display"); 
     c = this.getContentPane(); 
    } 

    public void addPanel(JPanel p) { 
     c.add(p); 
    } 

    public void showFrame() { 
     this.pack(); 
     this.setVisible(true); 
     this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
    } 
} 

我的代码:

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

public class DropPanel extends JPanel implements ActionListener{ 
    Timer ticker1= new Timer(20,this); 
    int x=150; 
    int y=0; 
    Timer ticker2= new Timer(20,this); 
    int x2=175; 
    int y2=0; 
    JButton drop=new JButton("Drop"); 
    JButton retrieve=new JButton("Retrieve"); 
    JButton quit=new JButton("Quit"); 

    public DropPanel(){ 
     setPreferredSize(new Dimension(300,600));  
     this.add(drop); drop.addActionListener(this); 
     this.add(retrieve); retrieve.addActionListener(this); 
     this.add(quit); quit.addActionListener(this); 
    } 

    public void paintComponent(Graphics g){ 
     super.paintComponent(g);  
     g.drawOval(x,y,50,50); 
     g.drawLine(x2,0,x2,y2); 
    } 

    public void actionPerformed (ActionEvent e){ 
     if(e.getSource() == ticker1){ 
      if (y<550) 
       y=y+2; 
     } 

     if(e.getSource() == drop){ 
      ticker1.start(); 
     }   

     if(e.getSource()== ticker2){ 
      if (y2<550){ 
       y2=y2+2; 
      } 
      if (y2==550) { 
       ticker1.stop(); 
       y=y-2; 
       y2=y2-2; 
      } 
     } 

     if(e.getSource() == retrieve){ 
      ticker2.start(); 
      if(y2==550){ 
       y2=y2-2; 
      } 
     } 

     if(e.getSource()==quit){ 
      System.exit(0); 
     }   
     repaint(); 
    } 
} 

这里是驱动程序:

public class DropDriver { 
    public static void main(String[] args) { 
     DisplayWindow d = new DisplayWindow(); 
     DropPanel b = new DropPanel(); 
     d.addPanel(b); 
     d.showFrame(); 
    } 
} 

回答

1

代码的格式使得它难以阅读,但我想我已经找到了错误:

if(e.getSource()== ticker2) { 
    if (y2<550) { 
    y2=y2+2; 
    } 

    if (y2==550) { 
    ticker1.stop(); 
    y=y-2; 
    y2=y2-2; 
    } 
} 

你有两个if语句,编译器将按照它们写入的顺序执行它们。所以当y2==550那么第二个if语句就会执行y2=y2-2,所以现在y2==448。现在,在接下来的蜱y2<550是真实的,因此第一个if语句将执行y2=y2+2所以现在y2==550,那么第二个if语句将执行y2=y2-2,所以现在y2==448 ...和球会继续上下移动2个像素。

我的建议是使用boolean,当球到达屏幕底部时,它被设置为true,并且只有当这个布尔值为假时才会执行第一个if语句。

1

从分离责任区开始。试图将你所有的“行为”逻辑混合成单一的方法不仅是糟糕的设计,它会给你造成很大的困惑。

每个计时器应该有它自己的ActionListener。这意味着您可以分离逻辑并专注于自己的工作单元,而不会不必要地混淆其他对象的状态。

例如...

import java.awt.BorderLayout; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.FlowLayout; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Point; 
import java.awt.Rectangle; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.geom.Ellipse2D; 
import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.Timer; 
import javax.swing.UIManager; 
import javax.swing.UnsupportedLookAndFeelException; 

public class DropBall { 

    public static void main(String[] args) { 
     new DropBall(); 
    } 

    public DropBall() { 
     EventQueue.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       try { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
       } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
       } 

       JFrame frame = new JFrame("Testing"); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setLayout(new BorderLayout()); 
       frame.add(new TestPane()); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 

    public class TestPane extends JPanel { 

     private JButton dropButton; 
     private JButton retrieveButton; 
     private AnimationPane animationPane; 

     public TestPane() { 
      setLayout(new BorderLayout()); 

      animationPane = new AnimationPane(); 
      add(animationPane); 

      dropButton = new JButton("Drop"); 
      dropButton.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (animationPane.canDrop()) { 
         animationPane.drop(); 
        } 
       } 
      }); 
      retrieveButton = new JButton("Retrieve"); 
      retrieveButton.addActionListener(new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        if (animationPane.canRetrieve()) { 
         animationPane.retrieve(); 
        } 
       } 
      }); 

      JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.CENTER)); 
      buttonPane.add(dropButton); 
      buttonPane.add(retrieveButton); 

      add(buttonPane, BorderLayout.SOUTH); 
     } 
    } 

    public static class AnimationPane extends JPanel { 

     protected static final int RUN_TIME = 1000; 
     private Timer dropTimer; 
     private Timer retrieveTimer; 
     private Ellipse2D ball; 
     private long startTime = -1; 
     private Point ballPoint; 
     private Point linePoint; 

     public AnimationPane() { 
      ball = new Ellipse2D.Float(0, 0, 10, 10); 

      dropTimer = new Timer(30, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        long duration = System.currentTimeMillis() - startTime; 
        float progress = (float) duration/(float) RUN_TIME; 

        if (progress > 1f) { 
         progress = 1f; 
         ((Timer) e.getSource()).stop(); 
        } 

        ballPoint = new Point(); 
        ballPoint.x = getWidth()/2; 
        ballPoint.y = Math.round(getHeight() * progress); 

        repaint(); 
       } 
      }); 
      dropTimer.setRepeats(true); 
      dropTimer.setCoalesce(true); 
      dropTimer.setInitialDelay(0); 

      retrieveTimer = new Timer(30, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 
        long duration = System.currentTimeMillis() - startTime; 
        float progress = (float) duration/(float) RUN_TIME; 

        linePoint = new Point(); 
        linePoint.x = getWidth()/2; 

        if (progress < 0.5f) { 
         linePoint.y = Math.round(getHeight() * (progress * 2)); 
        } else { 
         if (progress > 1f) { 
          progress = 1f; 
          ((Timer) e.getSource()).stop(); 
          linePoint = null; 
          ballPoint = null; 
         } else { 
          linePoint.y = Math.round(getHeight() * (progress * 2)); 
          linePoint.y = getHeight() - (linePoint.y - getHeight()); 

          ballPoint.y = linePoint.y; 
         } 
        } 

        repaint(); 
       } 
      }); 
      retrieveTimer.setRepeats(true); 
      retrieveTimer.setCoalesce(true); 
      retrieveTimer.setInitialDelay(0); 
     } 

     @Override 
     public Dimension getPreferredSize() { 
      return new Dimension(200, 200); 
     } 

     @Override 
     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      if (ballPoint != null) { 

       int x = (int) (ballPoint.x - (ball.getWidth()/2)); 
       int y = (int) (ballPoint.y - ball.getHeight()); 

       g2d.translate(x, y); 
       g2d.draw(ball); 
       g2d.translate(-x, -y); 

      } 
      if (linePoint != null) { 
       int x = getWidth()/2; 
       int y = 0; 

       g2d.drawLine(x, y, linePoint.x, linePoint.y); 
      } 
      g2d.dispose(); 
     } 

     public boolean canDrop() { 
      return !dropTimer.isRunning() && !retrieveTimer.isRunning() && ballPoint == null; 
     } 

     public boolean canRetrieve() { 
      return !dropTimer.isRunning() && !retrieveTimer.isRunning() && ballPoint != null; 
     } 

     public void drop() { 
      startTime = System.currentTimeMillis(); 
      dropTimer.start(); 
     } 

     public void retrieve() { 
      startTime = System.currentTimeMillis(); 
      retrieveTimer.start(); 
     } 
    } 
} 

这基本上使用两个独立的定时器来执行工作的各个单位。丢弃和检索。该功能是在这样的设置远,你只能获取一个球时,球已实际下降,但不能删除一个以上的球...