Java代码中的计时器问题

时间:2013-04-30 22:14:32

标签: java graphics timer actionlistener paintcomponent

对于家庭作业,我必须制作一个程序,其中一个窗口打开,有三个按钮:Drop,Retrieve和Quit。按下跌落时,圆圈从显示屏顶部落到底部并停留在那里。按下“检索”时,一条线应从屏幕向下落到圆圈,然后在视觉上将圆圈拉回到屏幕顶部。

我已经写了几乎所有我无法让线回到屏幕上的东西,在我的代码中只有球确实并且线路停留在那里。

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();
    }
}

2 个答案:

答案 0 :(得分: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。现在在下一个tick y2<550为真,所以第一个if语句将执行y2=y2+2所以现在y2==550,然后第二个if语句将执行y2=y2-2,所以现在{{1 ......并且球将继续上下移动2个像素。

我的建议是当球到达屏幕底部时使用设置为y2==448的{​​{1}},并且只有当此布尔值为false时才会执行第一个if语句。

答案 1 :(得分: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();
        }
    }
}

这基本上使用两个独立的计时器来执行各个工作单元。删除和检索。功能设置在这样的距离,你只能在一个球实际掉落时检索一个球,但不能丢球超过一个球...