Reputation: 25
I am working on a program for a class that I am taking. The program I am creating is a game. The program has a main class that extends frame. Inside that class I created a window that is setup as a border layout. In the CENTER of the border layout is a panel that also has a border layout. My second class, which extends canvas, is assigned to the second border layout's CENTER. In that canvas, I have an object that moves around the screen using the keyboard. Say for instance the following is my window and the O is the object moving around:
------------------------------------------------------------
|File____________________________________________________X_|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| O |
| |
| |
| |
| |
| |
|__________________________________________________________|
Is there a way to restrict the size of the window based on where the O is? I don't want to resize smaller than where the object is being rendered. If it matters, the O is stored as a Rectangle Object, and so is the border of the CENTER of the second border layout. I have the O staying in the border by using the Rectangle.contains method. After the O moves away from the border, I want the allowable size to be restricted even further.
Here is the code:
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
}
Upvotes: 0
Views: 337
Reputation: 347234
I was trying to find something a little more elegant, but couldn't quite make it work the way it should, so I ended up with a brute force method.
Basically, this adds a ComponentListener
to the Frame
and monitors for it's componentResized
event. It then compares the frame's size with the contents minimumSize
and makes sure that the size is never reduced beyond it (also taking into account the frame's borders).
I know this is in Swing, but the basic concept should apply to 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();
}
}
}
Okay, that took longer then it should have. I had to take your code apart and put it back together again. There were a number of fundamental mistakes and some "hard to find" assignments which kept giving mean erroneous results.
First, update
calls paint
, so your "painting" routine is backwards. update
should make sure that there is a offscreen buffer available and create one if required and then painting should be done to it's Graphics
context. I've played around with it a little and used a BufferedImage
instead ... because I'm lazy and it's a lot easier to deal with it.
Second, you MouseListener
s should be registered internally with the Screen
, the functionality it's trying to achieve is maintained internally by the class.
Calculating the minimum size based on the available Rectangle
s could be a little complicated, the basic idea is you want to combine them all together into one "super" shape and calculate it's bounds, lucky for you, a class exists to do that...
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);
Finally, after more mucky about then I really would like, I ended up with an observer pattern which triggers a notification when the "size constraint" may have changed. The Frame
then needs to calculate it's minimum size based on the available information it has (including both the Screen
, controls
and frame Insets
to determine it's minimums size...
So, you know, really easy :P
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());
}
}
Upvotes: 1