tags:

views:

39

answers:

1
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class dots extends JPanel implements KeyListener, ComponentListener{ //JPanel extended so that we can overwrite paintComponent and draw the dots, KeyListener so that we can capture keypresses
 Random rand = new Random(); 
 JFrame frame;
 boolean haveSize = false; //this is used to tell paintComponent whether or not we have the size of the drawable area
 int[] x = new int[18],y = new int[18]; //used to store x and y coordinates of the dots so that they don't change position every time paintComponent is called, which is unpredictable
 final int OVALDIAM = 40;

 public dots() {
  frame = new JFrame("Dots");
  frame.setSize(new Dimension(800,600)); //So that when we minimize, we don't get a little bar
  frame.setExtendedState(Frame.MAXIMIZED_BOTH); //Maximize the window
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Hiding the window is a dumb default close behavior. Oh well.
  frame.getContentPane().add(this); //put the JPanel in the JFrame
  frame.addComponentListener(this);
  addKeyListener(this); //The next three lines allow the JPanel to capture key presses and subsequently move the dots when a key is pressed
  setFocusable(true); 
  requestFocusInWindow();
  frame.setVisible(true);
  try { //for whatever reason, the JPanel (this) doesn't know it's height, which we need to accuratly place dots, immediately after calling setVisible, so we wait for a bit to let it figure things out
   Thread.sleep(50);
  }
  catch (Exception e) {}
  newPos();
  System.out.println("Press any button to rearrange the dots");
 }

 public void paintComponent(Graphics g) { 
  super.paintComponent(g); //draw background using the supers method
  if (haveSize) { //if we have the size of the window, then newPos has run and we can paint the dots
   for (int i = 0; i < 18; i++) { //loop to draw the dots
    g.setColor(i < 12 ? Color.YELLOW : Color.BLUE); //if we have drawn fewer than 12 dots, color them yellow, else, color them blue
    g.fillOval(x[i],y[i],OVALDIAM,OVALDIAM);
    //System.out.println((i < 12 ? "Yellow":"Blue") + " oval drawn at " + x[i] + "," + y[i]); //Debugging that gave location of dots (some where getting lost)
   }
  }
 }

 public void newPos() { //this method generates new and random locations for the dots
  for (int i = 0; i < 18; i++) {
   x[i] = rand.nextInt(getSize().getWidth() > OVALDIAM ? (int)getSize().getWidth() - OVALDIAM : (int)getSize().getWidth()); // we subtract OVALDIAM so that the entire dot fits in the screen. We also check to make sure that the area is >OVALDIAM
   y[i] = rand.nextInt(getSize().getHeight() > OVALDIAM ? (int)getSize().getHeight() - OVALDIAM : (int)getSize().getHeight());
  }
  if (!haveSize) { //if this method has run, then we can run paintComponent
   haveSize = true; //we have locations for dots so we can start drawing dots
   frame.repaint(); //ensure dots get painted
  }
 }

 public void componentResized(ComponentEvent e){
   newPos();
   frame.repaint();
 }

 public void keyPressed(KeyEvent e) { //when a button is pressed, move the dots
  newPos();
  frame.repaint();
 }

 //interface methods we don't need
 public void componentMoved(ComponentEvent e) {}
 public void componentShown(ComponentEvent e) {}
 public void componentHidden(ComponentEvent e) {}
 public void keyReleased(KeyEvent e){}
 public void keyTyped(KeyEvent e) {}

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

So I have this code, and it works fine. However, if you comment out

try { //for whatever reason, the JPanel (this) doesn't know it's height, which we need to accuratly place dots, immediately after calling setVisible, so we wait for a bit to let it figure things out
            Thread.sleep(50);
        }
        catch (Exception e) {}

you get an error. Works fine if you press a key, which updates everything, but otherwise it is weird. Any ideas why?

On an unrelated note, this code is going to help get me a job, so if any of you see anything wrong, please feel free to speak up.

+1  A: 

All drawing should be executed under the AWT thread as shown here and here you might want to get your painting code under dots() method to run under invokeLater() so it will manage to finish painting before querying for height or width.

Ido
Even using AWT entirely components (which are in some sense supposedly thread-safe, just with thousands of threading bugs), it would be a problem. The frame is laying itself out in a different thread (the EDT), so there is a race.
Tom Hawtin - tackline
Well, the even weirder part,which I left out in op is that you can get the width of the JPanel. It's just the height that is still set to 0. This makes me think that it is still figuring out the height of the task bar and everything else.
David Watson