限制Java

时间:2018-04-11 01:54:50

标签: java canvas awt

我正在为我正在上课的课程。我正在创建的程序是一款游戏。该程序有一个扩展框架的主类。在该类中,我创建了一个设置为边框布局的窗口。在边框布局的中心是一个也有边框布局的面板。我的第二个类,它扩展了canvas,被分配给第二个边框布局的CENTER。在那个画布中,我有一个使用键盘在屏幕上移动的对象。比如说以下是我的窗口,O是移动的对象:

------------------------------------------------------------
|File____________________________________________________X_|
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                          O               |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|                                                          |
|__________________________________________________________|

有没有办法根据O的位置来限制窗口的大小?我不想调整小于渲染对象的位置。如果重要,则O存储为矩形对象,第二个边框布局的CENTER边框也是如此。我使用Rectangle.contains方法让O停留在边框中。在O离开边界后,我希望进一步限制允许的大小。

以下是代码:

import java.awt.*;
import java.awt.event.*;
import java.util.Vector;
import static java.lang.Integer.min;

public class BouncingBall extends Frame
implements ActionListener, WindowListener, ComponentListener, AdjustmentListener, MouseListener, MouseMotionListener, Runnable {

private boolean done = false;
Thread theThread;

int sbVis = 10;
int sbMin = 1;
int sbMax = 100 + sbVis;
int sbUnitInc = 3;
int sbBlockInc = 20;
private final int DELAY = 10;
long delay = (long)(DELAY*(double)((sbMax - sbMin)/100));

private Panel canvas = new Panel();
private Panel control = new Panel();

Scrollbar speedSB;
Scrollbar sizeSB;
Button runBtn;
Button pauseBtn;
Button quitBtn;
Label speedLabel;
Label sizeLabel;
Screen s = new Screen();

Rectangle ZERORECT = new Rectangle(0,0,0,0);
private boolean newRect = true;
int x1, x2, y1, y2;


BouncingBall () {
    this.setLayout(new BorderLayout());
    canvas.setLayout(new BorderLayout());
    initComponents();
    this.setVisible(true);
    start();
}

//main function
public static void main(String[] args) {
    BouncingBall b = new BouncingBall();
} //end main function

private void initComponents () {
    //set up main frame layout and add the components to the correct location
    this.setTitle("Bouncing Ball");
    this.setSize(640,480);
    //this.setMinimumSize(new Dimension(640,480));
    this.add(canvas, BorderLayout.CENTER);
    this.add(control, BorderLayout.SOUTH);
    s.setBackground(Color.WHITE);
    canvas.add(s, BorderLayout.CENTER);

    //mouse listeners
    s.addMouseMotionListener(this);
    s.addMouseListener(this);

    //listeners on this frame
    this.addComponentListener(this);
    this.addWindowListener(this);

    //add buttons, scrollbars, and labels
    speedSB = new Scrollbar(Scrollbar.HORIZONTAL);
    speedSB.setMinimum(sbMin);
    speedSB.setMaximum(sbMax);
    speedSB.setVisibleAmount(sbVis);
    speedSB.setUnitIncrement(sbUnitInc);
    speedSB.setBlockIncrement(sbBlockInc);
    speedSB.addAdjustmentListener(this);
    sizeSB = new Scrollbar(Scrollbar.HORIZONTAL);
    sizeSB.setMinimum(15);
    sizeSB.setMaximum(sbMax);
    sizeSB.setVisibleAmount(sbVis);
    sizeSB.setUnitIncrement(sbUnitInc);
    sizeSB.setBlockIncrement(sbBlockInc);
    sizeSB.addAdjustmentListener(this);
    sizeSB.setValue(s.ball.width);
    runBtn = new Button("Run");
    runBtn.addActionListener(this);
    runBtn.setEnabled(false);
    pauseBtn = new Button("Pause");
    pauseBtn.addActionListener(this);
    quitBtn = new Button("Quit");
    quitBtn.addActionListener(this);
    speedLabel = new Label("Speed");
    sizeLabel = new Label("Size");


    //setup the layout of the control panel
    GridBagLayout lm = new GridBagLayout();
    control.setLayout(lm);

    GridBagConstraints c = new GridBagConstraints();
    c.fill = GridBagConstraints.HORIZONTAL;

    c.weightx = 1.0;
    c.gridx = 0;
    c.gridy = 0;
    c.insets = new Insets(10,30,5,30);
    control.add(speedSB, c);

    c.insets = new Insets(10,0,5,0);
    c.gridx = 1;
    c.gridy = 0;
    control.add(runBtn, c);

    c.gridx = 2;
    c.gridy = 0;
    control.add(pauseBtn, c);

    c.gridx = 3;
    c.gridy = 0;
    control.add(quitBtn, c);

    c.insets = new Insets(10,30,5,30);
    c.gridx = 4;
    c.gridy = 0;
    control.add(sizeSB, c);

    c.fill = GridBagConstraints.CENTER;
    c.insets = new Insets(0,0,0,0);
    c.gridx = 0;
    c.gridy = 1;
    control.add(speedLabel, c);

    c.gridx = 4;
    c.gridy = 1;
    control.add(sizeLabel, c);
    s.repaint();
}

public Rectangle makeRect () {
    int width = this.x1 - this.x2;
    int height = this.y1 - this.y2;
    Rectangle rect = new Rectangle(min(this.x1, this.x2),min(this.y1,this.y2),Math.abs(width),Math.abs(height));
    return rect;
}

public void run() {
    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    while (true) {
        try {
            theThread.sleep(0);
            while (!done) {//pause variable
                s.step();
                this.setMinimumSize(s.getMinimumSize());
                try {
                    theThread.sleep(delay); //move speed
                } catch (InterruptedException e) { }
            }
        } catch (InterruptedException e){}
    }
}

public void start() { //begin overloaded start()
    if (theThread == null) {
        theThread = new Thread(this);
        theThread.start();
    }
}

public void stop() {
    this.removeWindowListener(this);
    this.removeComponentListener(this);
    sizeSB.removeAdjustmentListener(this);
    speedSB.removeAdjustmentListener(this);
    s.removeMouseListener(this);
    s.removeMouseMotionListener(this);
    dispose();
    System.exit(0);
}//end stop()

//canvas object
public class Screen extends Canvas {
    Image buffer;
    Graphics og;
    Rectangle ball;
    Rectangle screen;
    int x = 1;
    int y = -1;
    Vector<Rectangle> rects = new Vector<Rectangle>();
    public Screen() {
        ball = new Rectangle(10,38,30,30);
        screen = new Rectangle();
    }

    public int ballX() {
        return ball.x;
    }

    public int ballY() {
        return ball.y;
    }

    public void addOne(Rectangle r) {
        Rectangle nr = new Rectangle(r);
        if (!nr.intersects(ball)) {
            if (nr.x + nr.width > screen.width-1) {
                nr.setSize((screen.width-1) - nr.x, nr.height);
            }
            if (nr.y + nr.height > screen.height-1) {
                nr.setSize(nr.width, (screen.height-1) - nr.y);
            }
            rects.addElement(nr);
        }
    }

    public void checkRemove (Point p) {
        Point np = new Point(p);
        for (int i = 0; i < rects.size(); i++) {
            if (rects.get(i).contains(np)) {
                rects.removeElementAt(i);
                i--;
            }
        }
    }

    public void step () {
        checkBorder();
        checkTouching();
        repaint();
    }

    public void checkBorder() {
        Rectangle temp = new Rectangle(ball);
        temp.grow(2,2);
        if (screen.contains(temp)) {
            ball.setLocation((int) ball.getX() + x, (int) ball.getY() + y);
        }
        else {
            if (ball.x + ball.width > screen.width-3) {
                x = -1;
            }
            if (ball.y + ball.height > screen.height-3) {
                y = -1;
            }
            if (ball.x < screen.x+2) {
                x = 1;
            }
            if (ball.y < screen.y+2) {
                y = 1;
            }
            ball.setLocation(ball.x + x, ball.y + y);
        }
    }

    public void checkTouching() {
        for (int i = 0; i < rects.size(); i++) {
            System.out.println("size: " + getMinimumSize().width);
            Rectangle b = new Rectangle(ball);
            b.grow(1,1);
            if(rects.get(i).intersects(b)) {
                int left = rects.get(i).x;
                int top = rects.get(i).y;
                int right = rects.get(i).x + rects.get(i).width;
                int bottom = rects.get(i).y + rects.get(i).height;
                if ((b.x + b.width) > left) {
                    System.out.println("x = " + x);
                    x=x * -1;
                    System.out.println("left");
                    System.out.println("x = " + x);
                }
                else if ((b.x < right)) {
                    System.out.println("right");
                    x=x * -1;
                }
                else if ((b.y + b.height) > top) {
                    System.out.println("top");
                    y=y * -1;
                }
                else if (b.y < bottom) {
                    System.out.println("bottom");
                    y=y * -1;
                }
            }
        }
    }

    public void setObjSize (int size) {
        ball.setSize(size,size);
    }

    public void resized() {
        screen.setBounds(this.getBounds());
        if (ball.x + ball.width > screen.width-3) {
            ball.setLocation(screen.width-ball.width-3,ball.y);
        }
        if (ball.y + ball.height > screen.height-3) {
            ball.setLocation(ball.x,screen.height-ball.height-3);
        }
        repaint();
    }

    @Override
    public void paint(Graphics g) {
        update(g);
    }

    @Override
    public void update(Graphics g) {
        if (og != null) {
            og.dispose();
        }
        buffer = createImage(screen.width, screen.height);
        og = buffer.getGraphics();
        super.paint(g);

        Rectangle rect = makeRect();
        og.setColor(Color.BLACK);
        if (!newRect) {
            og.fillRect(rect.x,rect.y,rect.width,rect.height);
        }
        for (Rectangle drawRect : this.rects) {
            og.fillRect(drawRect.x,drawRect.y,drawRect.width,drawRect.height);
        }

        //draw the screen border
        og.setColor(Color.RED);
        og.drawRect(screen.x,screen.y,screen.width-1,screen.height-1);
        //draw the ball
        og.setColor(Color.LIGHT_GRAY);
        og.fillOval(ball.x,ball.y,ball.width,ball.height);
        og.setColor(Color.BLACK);
        og.drawOval(ball.x,ball.y,ball.width,ball.height);
        g.drawImage(buffer,0,0,null);
    }

    @Override
    public Dimension getMinimumSize() {
        for(Rectangle temp : this.rects) {

        }
    }
}

//overloaded listeners
public void actionPerformed(ActionEvent e) {
    Object o = e.getSource();
    if (o == quitBtn) {
        stop();
    }
    else if (o == runBtn) {
        done = false;
        runBtn.setEnabled(false);
        pauseBtn.setEnabled(true);
    }
    else if (o == pauseBtn) {
        done = true;
        runBtn.setEnabled(true);
        pauseBtn.setEnabled(false);
    }
}

public void adjustmentValueChanged(AdjustmentEvent e) {
    Object obj = e.getSource();
    if (obj == sizeSB) {
        int objSize;
        int maxSize = min(s.getWidth()-s.ballX(), s.getHeight()-s.ballY());
        if(maxSize > e.getValue()) {
            objSize = e.getValue();
            s.setObjSize(objSize);
        }
        else {
            objSize = maxSize;
            s.setObjSize(objSize);
            sizeSB.setValue(objSize);
        }
    }
    if (obj == speedSB) {
        int speed = e.getValue();
        delay = (long) (DELAY*(double)(sbMax - speed + 1)/100);
        theThread.interrupt();
    }
}

public void componentResized(ComponentEvent e) {
    s.resized();
    System.out.println(s.getHeight());
}

public void componentMoved(ComponentEvent e) {

}

public void componentShown(ComponentEvent e) {

}

public void componentHidden(ComponentEvent e) {

}

public void mouseClicked(MouseEvent e) {
    Point p = new Point(e.getX(),e.getY());
    s.checkRemove(p);
}

public void mousePressed(MouseEvent e) {
    this.x1 = e.getX();
    this.y1 = e.getY();
    System.out.println("x1 = " + x1);
    System.out.println("y1 = " + y1);
    s.repaint();
}

public void mouseReleased(MouseEvent e) {
    this.x2 = e.getX();
    this.y2 = e.getY();
    Rectangle rect = makeRect();
    if (rect.height != 0 || rect.width != 0) {
        s.addOne(rect);
    }
    x1 = 0;
    x2 = 0;
    y1 = 0;
    y2 = 0;
    this.newRect = true;
    s.repaint();
}

public void mouseEntered(MouseEvent e) {

}

public void mouseExited(MouseEvent e) {

}

public void mouseDragged(MouseEvent e) {
    this.x2 = e.getX();
    this.y2 = e.getY();
    this.newRect = false;
    s.repaint();
}

public void mouseMoved(MouseEvent e) {

}

public void windowOpened(WindowEvent e) {

}

public void windowClosing(WindowEvent e) {
    stop();
}

public void windowClosed(WindowEvent e) {

}

public void windowIconified(WindowEvent e) {

}

public void windowDeiconified(WindowEvent e) {

}

public void windowActivated(WindowEvent e) {

}

public void windowDeactivated(WindowEvent e) {

}
//end overloaded listeners

}

1 个答案:

答案 0 :(得分:1)

我试图找到一些更优雅的东西,但不能让它按照应有的方式工作,所以我最终采用了蛮力方法。

基本上,这会为ComponentListener添加Frame并监控其componentResized事件。然后它将帧的大小与内容minimumSize进行比较,并确保大小永远不会超出它(同时考虑到帧的边界)。

我知道这是在Swing中,但基本概念应该适用于AWT

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

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

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

                JFrame frame = new JFrame("Testing");
                frame.add(new TestPane());
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.addComponentListener(new ComponentAdapter() {
                    private boolean ignoreNext = false;
                    @Override
                    public void componentResized(ComponentEvent e) {
                        if (ignoreNext) {
                            ignoreNext = false;
                            return;
                        }
                        Insets insets = frame.getInsets();
                        ignoreNext = true;
                        int width = Math.max(frame.getWidth(), frame.getContentPane().getMinimumSize().width + (insets.left + insets.right));
                        int height = Math.max(frame.getHeight(), frame.getContentPane().getMinimumSize().height + (insets.top + insets.bottom));
                        frame.setSize(width, height);
                    }
                });
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Rectangle rect;

        public TestPane() {
            MouseAdapter ma = new MouseAdapter() {
                private Point anchor;

                @Override
                public void mouseDragged(MouseEvent e) {
                    Point p = e.getPoint();
                    int minX = Math.min(anchor.x, p.x);
                    int minY = Math.min(anchor.y, p.y);
                    int maxX = Math.max(anchor.x, p.x);
                    int maxY = Math.max(anchor.y, p.y);

                    rect = new Rectangle(minX, minY, maxX - minX, maxY - minY);
                    repaint();
                    revalidate();
                }

                @Override
                public void mousePressed(MouseEvent e) {
                    anchor = e.getPoint();
                }

                @Override
                public void mouseReleased(MouseEvent e) {
                    anchor = null;
                }
            };
            addMouseMotionListener(ma);
            addMouseListener(ma);
        }

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

        @Override
        public Dimension getMinimumSize() {
            if (rect == null) {
                return super.getMinimumSize();
            }
            Dimension size = new Dimension(rect.x + rect.width, rect.y + rect.height);
            return size;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (rect == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLUE);
            g2d.fill(rect);
            g2d.dispose();
        }

    }

}

根据可用代码更新......

好的,这需要更长的时间。我不得不把你的代码分开并再次把它重新组合在一起。有一些基本错误和一些“难以找到”的任务,这些错误一直给出错误的结果。

首先,update调用paint,因此您的“绘画”例程会倒退。 update应该确保有一个可用的屏幕外缓冲区并根据需要创建一个,然后应该对它的Graphics上下文进行绘制。我已经玩了一点而且使用了BufferedImage代替...因为我很懒,而且处理起来要容易得多。

其次,你MouseListener应该在Screen内部注册,它试图实现的功能由类内部维护。

根据可用的Rectangle计算最小尺寸可能有点复杂,基本的想法是你想将它们组合成一个“超级”形状并计算它的界限,幸运的是你,a这样做是存在的......

Area area = new Area();
for (Rectangle temp : this.rects) {
    System.out.println(temp);
    area.add(new Area(temp));
}
Rectangle bounds = area.getBounds();
System.out.println("bounds = " + bounds);
Dimension size = new Dimension(bounds.x + bounds.width, bounds.y + bounds.height);

最后,经过更多的愚蠢然后我真的想,我最终得到一个观察者模式,当“大小约束”可能已经改变时触发通知。然后,Frame需要根据其可用信息计算最小尺寸(包括Screencontrols和框架Insets,以确定其最小尺寸......

所以,你知道,非常简单:P

BouncingBall

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.Scrollbar;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import static java.lang.Math.min;

public class BouncingBall extends Frame
                implements ActionListener, AdjustmentListener, Runnable {

    private boolean done = false;
    Thread theThread;

    int sbVis = 10;
    int sbMin = 1;
    int sbMax = 100 + sbVis;
    int sbUnitInc = 3;
    int sbBlockInc = 20;
    private final int DELAY = 10;
    long delay = (long) (DELAY * (double) ((sbMax - sbMin) / 100));

//  private Panel canvas = new Panel();
    private Panel control = new Panel();

    Scrollbar speedSB;
    Scrollbar sizeSB;
    Button runBtn;
    Button pauseBtn;
    Button quitBtn;
    Label speedLabel;
    Label sizeLabel;
    Screen s = new Screen();

    Rectangle ZERORECT = new Rectangle(0, 0, 0, 0);
    private boolean newRect = true;
    int x1, x2, y1, y2;

    BouncingBall() {
        this.setLayout(new BorderLayout());
//      canvas.setLayout(new BorderLayout());
        initComponents();
        this.setVisible(true);
        start();
    }

//main function
    public static void main(String[] args) {
        BouncingBall b = new BouncingBall();
    } //end main function

    private void initComponents() {
        //set up main frame layout and add the components to the correct location
        this.setTitle("Bouncing Ball");
        this.setSize(640, 480);

        this.add(s, BorderLayout.CENTER);
        this.add(control, BorderLayout.SOUTH);
        s.setBackground(Color.WHITE);

        s.setConstraintListener(new Screen.ConstraintListener() {
            @Override
            public void constraintsChanged(Dimension size) {
                System.out.println("Size = " + size);
                Insets insets = getInsets();
                int minWidth = size.width + (insets.left + insets.right);
                int minHeight = size.height + control.getPreferredSize().height + (insets.top + insets.bottom);
                System.out.println(minWidth + " - " + minHeight);
                setMinimumSize(new Dimension(minWidth, minHeight));
            }
        });

//      canvas.add(s, BorderLayout.CENTER);

        //listeners on this frame
//      this.addComponentListener(new ComponentAdapter() {
//          private boolean ignoreNext = false;
//          @Override
//          public void componentResized(ComponentEvent e) {
//              if (ignoreNext) {
//                  ignoreNext = false;
//                  return;
//              }
//              Insets insets = getInsets();
//              ignoreNext = true;
//              int minWidth = canvas.getMinimumSize().width;
//              int minHeight = canvas.getMinimumSize().height + control.getPreferredSize().height;
//              int width = Math.max(getWidth(), minWidth + (insets.left + insets.right));
//              int height = Math.max(getHeight(), minHeight + (insets.top + insets.bottom));
//              setSize(width, height);
//          }
//      });
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                stop();
            }
        });

        //add buttons, scrollbars, and labels
        speedSB = new Scrollbar(Scrollbar.HORIZONTAL);
        speedSB.setMinimum(sbMin);
        speedSB.setMaximum(sbMax);
        speedSB.setVisibleAmount(sbVis);
        speedSB.setUnitIncrement(sbUnitInc);
        speedSB.setBlockIncrement(sbBlockInc);
        speedSB.addAdjustmentListener(this);
        sizeSB = new Scrollbar(Scrollbar.HORIZONTAL);
        sizeSB.setMinimum(15);
        sizeSB.setMaximum(sbMax);
        sizeSB.setVisibleAmount(sbVis);
        sizeSB.setUnitIncrement(sbUnitInc);
        sizeSB.setBlockIncrement(sbBlockInc);
        sizeSB.addAdjustmentListener(this);
        sizeSB.setValue(s.ball.width);
        runBtn = new Button("Run");
        runBtn.addActionListener(this);
        runBtn.setEnabled(false);
        pauseBtn = new Button("Pause");
        pauseBtn.addActionListener(this);
        quitBtn = new Button("Quit");
        quitBtn.addActionListener(this);
        speedLabel = new Label("Speed");
        sizeLabel = new Label("Size");

        //setup the layout of the control panel
        GridBagLayout lm = new GridBagLayout();
        control.setLayout(lm);

        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;

        c.weightx = 1.0;
        c.gridx = 0;
        c.gridy = 0;
        c.insets = new Insets(10, 30, 5, 30);
        control.add(speedSB, c);

        c.insets = new Insets(10, 0, 5, 0);
        c.gridx = 1;
        c.gridy = 0;
        control.add(runBtn, c);

        c.gridx = 2;
        c.gridy = 0;
        control.add(pauseBtn, c);

        c.gridx = 3;
        c.gridy = 0;
        control.add(quitBtn, c);

        c.insets = new Insets(10, 30, 5, 30);
        c.gridx = 4;
        c.gridy = 0;
        control.add(sizeSB, c);

        c.fill = GridBagConstraints.CENTER;
        c.insets = new Insets(0, 0, 0, 0);
        c.gridx = 0;
        c.gridy = 1;
        control.add(speedLabel, c);

        c.gridx = 4;
        c.gridy = 1;
        control.add(sizeLabel, c);
        s.repaint();
    }

    public Rectangle makeRect() {
        int width = this.x1 - this.x2;
        int height = this.y1 - this.y2;
        Rectangle rect = new Rectangle(min(this.x1, this.x2), min(this.y1, this.y2), Math.abs(width), Math.abs(height));
        return rect;
    }

    public void run() {
        Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
        while (true) {
            try {
                theThread.sleep(0);
                while (!done) {//pause variable
                    s.step();
                    try {
                        theThread.sleep(delay); //move speed
                    } catch (InterruptedException e) {
                    }
                }
            } catch (InterruptedException e) {
            }
        }
    }

    public void start() { //begin overloaded start()
        if (theThread == null) {
            theThread = new Thread(this);
            theThread.start();
        }
    }

    public void stop() {
        sizeSB.removeAdjustmentListener(this);
        speedSB.removeAdjustmentListener(this);
        dispose();
        System.exit(0);
    }//end stop()

//canvas object
//overloaded listeners
    public void actionPerformed(ActionEvent e) {
        Object o = e.getSource();
        if (o == quitBtn) {
            stop();
        } else if (o == runBtn) {
            done = false;
            runBtn.setEnabled(false);
            pauseBtn.setEnabled(true);
        } else if (o == pauseBtn) {
            done = true;
            runBtn.setEnabled(true);
            pauseBtn.setEnabled(false);
        }
    }

    public void adjustmentValueChanged(AdjustmentEvent e) {
        Object obj = e.getSource();
        if (obj == sizeSB) {
            int objSize;
            int maxSize = min(s.getWidth() - s.ballX(), s.getHeight() - s.ballY());
            if (maxSize > e.getValue()) {
                objSize = e.getValue();
                s.setObjSize(objSize);
            } else {
                objSize = maxSize;
                s.setObjSize(objSize);
                sizeSB.setValue(objSize);
            }
        }
        if (obj == speedSB) {
            int speed = e.getValue();
            delay = (long) (DELAY * (double) (sbMax - speed + 1) / 100);
            theThread.interrupt();
        }
    }
//end overloaded listeners
}

屏幕

//canvas object
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class Screen extends Canvas {

    Rectangle ball;
    Vector<Rectangle> rects = new Vector<Rectangle>();
    int x = 1;
    int y = -1;

    private BufferedImage buffer;
    private Rectangle temp;

    public Screen() {
        ball = new Rectangle(10, 38, 30, 30);

        MouseAdapter ma = new MouseAdapter() {

            private Point anchor;

            public void mouseClicked(MouseEvent e) {
                Point p = new Point(e.getX(), e.getY());
                checkRemove(p);
            }

            public void mousePressed(MouseEvent e) {
                anchor = new Point(e.getPoint());
            }

            public void mouseReleased(MouseEvent e) {
                anchor = null;
                if (temp != null) {
                    addOne(temp);
                }
                temp = null;
                repaint();
            }

            public void mouseDragged(MouseEvent e) {
                Point p = e.getPoint();
                int minX = Math.min(anchor.x, p.x);
                int minY = Math.min(anchor.y, p.y);
                int maxX = Math.max(anchor.x, p.x);
                int maxY = Math.max(anchor.y, p.y);

                temp = new Rectangle(minX, minY, maxX - minX, maxY - minY);
                repaint();
            }
        };
        addMouseListener(ma);
        addMouseMotionListener(ma);
    }

    public int ballX() {
        return ball.x;
    }

    public int ballY() {
        return ball.y;
    }

    public void addOne(Rectangle r) {
        Rectangle nr = new Rectangle(r);
        if (!nr.intersects(ball)) {
            if (nr.x + nr.width > getWidth() - 1) {
                nr.setSize((getWidth() - 1) - nr.x, nr.height);
            }
            if (nr.y + nr.height > getHeight() - 1) {
                nr.setSize(nr.width, (getHeight() - 1) - nr.y);
            }
            rects.addElement(nr);
        }
        setMinimumSize(calculateMinimumSize());
        constraintsChanged();
    }

    public void checkRemove(Point p) {
        Point np = new Point(p);
        for (int i = 0; i < rects.size(); i++) {
            if (rects.get(i).contains(np)) {
                rects.removeElementAt(i);
                i--;
            }
        }
        setMinimumSize(calculateMinimumSize());
        constraintsChanged();
    }

    public void step() {
        checkBorder();
        checkTouching();
        repaint();
    }

    public void checkBorder() {
        Rectangle tempBall = new Rectangle(ball);
        tempBall.grow(2, 2);
        Rectangle screen = new Rectangle(new Point(0, 0), getSize());
        if (screen.contains(tempBall)) {
            ball.setLocation((int) ball.getX() + x, (int) ball.getY() + y);
        } else {
            if (ball.x + ball.width > screen.width - 3) {
                x = -1;
            }
            if (ball.y + ball.height > screen.height - 3) {
                y = -1;
            }
            if (ball.x < screen.x + 2) {
                x = 1;
            }
            if (ball.y < screen.y + 2) {
                y = 1;
            }
            ball.setLocation(ball.x + x, ball.y + y);
        }
    }

    public void checkTouching() {
        if (temp != null) {
            rects.add(temp);
        }
        for (int i = 0; i < rects.size(); i++) {
            Rectangle b = new Rectangle(ball);
            b.grow(1, 1);
            if (rects.get(i).intersects(b)) {
                int left = rects.get(i).x;
                int top = rects.get(i).y;
                int right = rects.get(i).x + rects.get(i).width;
                int bottom = rects.get(i).y + rects.get(i).height;
                if ((b.x + b.width) > left) {
                    x = x * -1;
                } else if ((b.x < right)) {
                    x = x * -1;
                } else if ((b.y + b.height) > top) {
                    y = y * -1;
                } else if (b.y < bottom) {
                    y = y * -1;
                }
            }
        }
        if (temp != null) {
            rects.remove(temp);
        }
    }

    public void setObjSize(int size) {
        ball.setSize(size, size);
    }

    @Override
    public void invalidate() {
        super.invalidate(); 
        buffer = null;
        resized();
    }

    public void resized() {
        if (ball.x + ball.width > getWidth() - 3) {
            ball.setLocation(getWidth() - ball.width - 3, ball.y);
        }
        if (ball.y + ball.height > getHeight() - 3) {
            ball.setLocation(ball.x, getHeight() - ball.height - 3);
        }
        repaint();
    }

    @Override
    public void paint(Graphics g) {
        Graphics2D g2d = (Graphics2D) g.create();
        super.paint(g2d);
        g2d.setColor(getBackground());
        g2d.fillRect(0, 0, getWidth(), getHeight());
        g2d.setColor(Color.BLACK);
        if (temp != null) {
            g2d.fill(temp);
        }
        for (Rectangle drawRect : this.rects) {
            g2d.fill(drawRect);
        }

        //draw the screen border
        g2d.setColor(Color.RED);
        g2d.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
        //draw the ball
        g2d.setColor(Color.LIGHT_GRAY);
        g2d.fillOval(ball.x, ball.y, ball.width, ball.height);
        g2d.setColor(Color.BLACK);
        g2d.drawOval(ball.x, ball.y, ball.width, ball.height);
        g2d.dispose();
    }

    @Override
    public void update(Graphics g) {
        if (buffer == null) {
            buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
        }
        Graphics2D g2d = buffer.createGraphics();
        super.update(g2d);
        g2d.dispose();
        g.drawImage(buffer, 0, 0, null);
    }

    protected Dimension calculateMinimumSize() {
        Area area = new Area();
        for (Rectangle temp : this.rects) {
            System.out.println(temp);
            area.add(new Area(temp));
        }
        Rectangle bounds = area.getBounds();
        System.out.println("bounds = " + bounds);
        Dimension size = new Dimension(bounds.x + bounds.width, bounds.y + bounds.height);
        return size;
    }

    public interface ConstraintListener {
        public void constraintsChanged(Dimension size);
    }

    private ConstraintListener listener;

    public void setConstraintListener(ConstraintListener listener) {
        this.listener = listener;
    }

    protected void constraintsChanged() {
        if (listener == null) {
            return;
        }
        listener.constraintsChanged(getMinimumSize());
    }
}