Files
G4G0-1/Semester 1/Programming 1/Java/examples/projects/chapter12/foxes-and-rabbits-graph/GridView.java
2024-01-15 20:14:10 +00:00

223 lines
6.7 KiB
Java
Executable File

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.HashMap;
import java.util.Map;
/**
* A graphical view of the simulation grid.
* The view displays a colored rectangle for each location representing its contents.
* Colors for each type of species can be defined using the setColor method.
*
* @author Michael Kölling and David J. Barnes
* @version 2016.03.18
*/
public class GridView extends JFrame implements SimulatorView
{
// Colors used for empty locations.
private static final Color EMPTY_COLOR = Color.white;
// Color used for objects that have no defined color.
private static final Color UNKNOWN_COLOR = Color.gray;
private final String STEP_PREFIX = "Step: ";
private final String POPULATION_PREFIX = "Population: ";
private JLabel stepLabel, population;
private FieldView fieldView;
// A map for storing colors for participants in the simulation
private Map<Class<?>, Color> colors;
// A statistics object computing and storing simulation information
private FieldStats stats;
/**
* Create a view of the given width and height.
* @param height The simulation's height.
* @param width The simulation's width.
*/
public GridView(int height, int width)
{
stats = new FieldStats();
colors = new HashMap<>();
setTitle("Fox and Rabbit Simulation");
stepLabel = new JLabel(STEP_PREFIX, JLabel.CENTER);
population = new JLabel(POPULATION_PREFIX, JLabel.CENTER);
setLocation(20, 50);
fieldView = new FieldView(height, width);
Container contents = getContentPane();
contents.add(stepLabel, BorderLayout.NORTH);
contents.add(fieldView, BorderLayout.CENTER);
contents.add(population, BorderLayout.SOUTH);
pack();
setVisible(true);
}
/**
* Define a color to be used for a given class of animal.
* @param animalClass The animal's Class object.
* @param color The color to be used for the given class.
*/
public void setColor(Class<?> animalClass, Color color)
{
colors.put(animalClass, color);
}
/**
* @return The color to be used for a given class of animal.
*/
private Color getColor(Class<?> animalClass)
{
Color col = colors.get(animalClass);
if(col == null) {
// no color defined for this class
return UNKNOWN_COLOR;
}
else {
return col;
}
}
/**
* Show the current status of the field.
* @param step Which iteration step it is.
* @param field The field whose status is to be displayed.
*/
public void showStatus(int step, Field field)
{
if(!isVisible()) {
setVisible(true);
}
stepLabel.setText(STEP_PREFIX + step);
stats.reset();
fieldView.preparePaint();
for(int row = 0; row < field.getDepth(); row++) {
for(int col = 0; col < field.getWidth(); col++) {
Object animal = field.getObjectAt(row, col);
if(animal != null) {
Class<?> cls = animal.getClass();
stats.incrementCount(cls);
fieldView.drawMark(col, row, getColor(cls));
}
else {
fieldView.drawMark(col, row, EMPTY_COLOR);
}
}
}
stats.countFinished();
population.setText(POPULATION_PREFIX + stats.getPopulationDetails(field));
fieldView.repaint();
}
/**
* Determine whether the simulation should continue to run.
* @return true If there is more than one species alive.
*/
public boolean isViable(Field field)
{
return stats.isViable(field);
}
/**
* Prepare for a new run.
*/
public void reset()
{
stats.reset();
}
/**
* Provide a graphical view of a rectangular field. This is
* a nested class (a class defined inside a class) which
* defines a custom component for the user interface. This
* component displays the field.
* This is rather advanced GUI stuff - you can ignore this
* for your project if you like.
*/
private class FieldView extends JPanel
{
private final int GRID_VIEW_SCALING_FACTOR = 6;
private int gridWidth, gridHeight;
private int xScale, yScale;
Dimension size;
private Graphics g;
private Image fieldImage;
/**
* Create a new FieldView component.
*/
public FieldView(int height, int width)
{
gridHeight = height;
gridWidth = width;
size = new Dimension(0, 0);
}
/**
* Tell the GUI manager how big we would like to be.
*/
public Dimension getPreferredSize()
{
return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
gridHeight * GRID_VIEW_SCALING_FACTOR);
}
/**
* Prepare for a new round of painting. Since the component
* may be resized, compute the scaling factor again.
*/
public void preparePaint()
{
if(! size.equals(getSize())) { // if the size has changed...
size = getSize();
fieldImage = fieldView.createImage(size.width, size.height);
g = fieldImage.getGraphics();
xScale = size.width / gridWidth;
if(xScale < 1) {
xScale = GRID_VIEW_SCALING_FACTOR;
}
yScale = size.height / gridHeight;
if(yScale < 1) {
yScale = GRID_VIEW_SCALING_FACTOR;
}
}
}
/**
* Paint on grid location on this field in a given color.
*/
public void drawMark(int x, int y, Color color)
{
g.setColor(color);
g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
}
/**
* The field view component needs to be redisplayed. Copy the
* internal image to screen.
*/
public void paintComponent(Graphics g)
{
if(fieldImage != null) {
Dimension currentSize = getSize();
if(size.equals(currentSize)) {
g.drawImage(fieldImage, 0, 0, null);
}
else {
// Rescale the previous image.
g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
}
}
}
}
}