import javax.swing.*; import java.awt.*; public class GridDisplay extends JPanel implements Runnable { // OVERVIEW: A GridDisplay is a subtype of JPanel for displaying a Grid. private Grid grid; //@invariant grid != null private SimObjectChooser simobjchooser; //@invariant simobjchooser != null private boolean stopThread; final static int SLEEP_DELAY = 200; //@requires grid != null //@requires simobjchooser != null GridDisplay(Grid grid, SimObjectChooser simobjchooser) { this.grid = grid; this.simobjchooser = simobjchooser; this.stopThread = true; setOpaque(false); // This is necessary to make painting work } final public Grid getGrid() // REQUIRES: init has previously been called for this. // EFFECTS: Returns the grid containing this cell. // NOTE: The rep is exposed. The Grid associated with a SimObject is part of the data abstraction. //@requires isInitialized; //@ensures \result != null; { return grid; } private int getSquareWidth() //@ensures \result > 0 { int swidth = getWidth() / grid.numHorizontal(); if (swidth > 0) { return swidth; } else { return 1; } } private int getSquareHeight() //@ensures \result > 0 { int sheight = getHeight() / grid.numVertical(); if (sheight > 0) { return sheight; } else { return 1; } } private int getHorizontalOffset() { return (getWidth() - (getSquareWidth() * grid.numHorizontal())) / 2; } private int getVerticalOffset() { return (getHeight() - (getSquareHeight() * grid.numVertical())) / 2; } public void setObjectAt(int display_x, int display_y) { if (stopThread) { // Only allow grid locations to be set if // the simulation is stopped. int square_y = (display_y - getVerticalOffset()) / getSquareHeight(); int square_x = (display_x - getHorizontalOffset()) / getSquareWidth(); SimObject newObject; try { Class c = simobjchooser.getSelectedClass(); if (c != null) { newObject = (SimObject) (c.newInstance()); //@nowarn Cast } else { System.err.println("Null object chooser!"); return; } //@nowarn Cast; } catch (InstantiationException e) { System.err.println("InstantiationException: " + e); e.printStackTrace(); return; } catch (IllegalAccessException e) { System.err.println("IllegalAccessException: " + e); e.printStackTrace(); return; } //@assume newObject != null; //@assume !newObject.isInitialized; // ESC/Java doesn't know about newInstance newObject.init(square_x, square_y, grid); try { grid.setObjectAt(square_x, square_y, newObject); } catch (BadLocationException ble) { // This should never happen System.err.println( "Bad location: " + square_x + ", " + square_y); System.exit(-1); } repaint(); } } public void startObjects() { grid.startObjects(); // Start SimObject threads. Thread displayThread = new Thread(this); displayThread.start(); } public void run() { stopThread = false; while (!stopThread) { repaint(); try { Thread.sleep(SLEEP_DELAY); } catch (java.lang.InterruptedException e) { System.out.println("Display thread interrupted."); break; } } } public void pauseObjects() { grid.pauseObjects(); // Pause SimObject threads. this.stopThread = true; } public void paintComponent(Graphics g) throws RuntimeException { //@ assume g != null; int squarewidth = getSquareWidth(); int squareheight = getSquareHeight(); int hoffset = getHorizontalOffset(); int voffset = getVerticalOffset(); //System.err.println("inside displaygrid" + grid.getScore()); for (int y = 0; y < grid.numVertical(); y++) { for (int x = 0; x < grid.numHorizontal(); x++) { SimObject tmp = grid.grabObjectAt(x, y); if (tmp == null) { g.setColor(Color.black); } else { g.setColor(tmp.getColor()); } g.fillRect( hoffset + x * squarewidth, voffset + y * squareheight, squarewidth - 1, squareheight - 1); } } } } //Class borrowed from Saturday Night Simulator and PS5 on CS201J website