2013-04-30 75 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(); 
     } 
    } 
} 

這基本上使用兩個獨立的定時器來執行工作的各個單位。丟棄和檢索。該功能是在這樣的設置遠,你只能獲取一個球時,球已實際下降,但不能刪除一個以上的球...