0

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

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

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

2 回答 2

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

这基本上使用两个单独的计时器来执行各个工作单元。丢弃和检索。该功能设置为您只能在实际掉落球时取回球,但不能掉落超过一个球......

于 2013-05-01T00:44:49.640 回答
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 个像素。

我的建议是使用 aboolean设置为true当球到达屏幕底部时,第一个 if 语句仅在此布尔值为 false 时执行。

于 2013-04-30T22:26:57.617 回答