I want to place the text section CONTROLS to the right instead of it just being listed, I'm a newbie and I'm using a source code from a website that publishes Java game codes. The Y coordinate exists but I can't seem to find the X coordinate which will help me to position the text section. This is the code for my side panel class:
/**
* The number of rows and columns in the preview window. Set to
* 5 because we can show any piece with some sort of padding.
*/
private static final int TILE_COUNT = 5;
/**
* The center x of the next piece preview box.
*/
private static final int SQUARE_CENTER_X = 130;
/**
* The center y of the next piece preview box.
*/
private static final int SQUARE_CENTER_Y = 65;
/**
* The size of the next piece preview box.
*/
private static final int SQUARE_SIZE = (TILE_SIZE * TILE_COUNT >> 1);
/**
* The number of pixels used on a small insets (generally used for categories).
*/
private static final int SMALL_INSET = 20;
/**
* The number of pixels used on a large insets.
*/
private static final int LARGE_INSET = 30;
/**
* The y coordinate of the stats category.
*/
private static final int STATS_INSET = 100;
/**
* The y coordinate of the controls category.
*/
private static final int CONTROLS_INSET = 175;
/**
* The number of pixels to offset between each string.
*/
private static final int TEXT_STRIDE = 25;
/**
* The small font.
*/
private static final Font SMALL_FONT = new Font("Arial", Font.BOLD, 11);
/**
* The large font.
*/
private static final Font LARGE_FONT = new Font("Arial", Font.BOLD, 13);
/**
* The color to draw the text and preview box in.
*/
private static final Color DRAW_COLOR = new Color(128, 192, 128);
/**
* The Tetris instance.
*/
private Tetris tetris;
/**
* Creates a new SidePanel and sets it's display properties.
* #param tetris The Tetris instance to use.
*/
public SidePanel(Tetris tetris) {
this.tetris = tetris;
setPreferredSize(new Dimension(200, BoardPanel.PANEL_HEIGHT));
setBackground(Color.BLACK);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//Set the color for drawing.
g.setColor(Color.WHITE);
/*
* This variable stores the current y coordinate of the string.
* This way we can re-order, add, or remove new strings if necessary
* without needing to change the other strings.
*/
int offset;
/*
* Draw the "Stats" category.
*/
g.setFont(LARGE_FONT);
g.drawString("Stats", SMALL_INSET, offset = STATS_INSET);
g.setFont(SMALL_FONT);
g.drawString("Level: " + tetris.getLevel(), LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("Score: " + tetris.getScore(), LARGE_INSET, offset += TEXT_STRIDE);
/*
* Draw the "Controls" category.
*/
g.setFont(LARGE_FONT);
g.drawString("Controls", SMALL_INSET, offset = CONTROLS_INSET);
g.setFont(SMALL_FONT);
g.drawString(" Left- Move Left", LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("Right - Move Right", LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("Z - Rotate Anticlockwise", LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("X - Rotate Clockwise", LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("Down - Drop", LARGE_INSET, offset += TEXT_STRIDE);
g.drawString("P - Pause Game", LARGE_INSET, offset += TEXT_STRIDE);
/*
* Draw the next piece preview box.
*/
g.setFont(LARGE_FONT);
g.drawString("Next Piece:", SMALL_INSET, 70);
g.drawRect(SQUARE_CENTER_X - SQUARE_SIZE, SQUARE_CENTER_Y - SQUARE_SIZE, SQUARE_SIZE * 2, SQUARE_SIZE * 2);
/*
* Draw a preview of the next piece that will be spawned. The code is pretty much
* identical to the drawing code on the board, just smaller and centered, rather
* than constrained to a grid.
*/
TileType type = tetris.getNextPieceType();
if(!tetris.isGameOver() && type != null) {
/*
* Get the size properties of the current piece.
*/
int cols = type.getCols();
int rows = type.getRows();
int dimension = type.getDimension();
/*
* Calculate the top left corner (origin) of the piece.
*/
int startX = (SQUARE_CENTER_X - (cols * TILE_SIZE / 2));
int startY = (SQUARE_CENTER_Y - (rows * TILE_SIZE / 2));
/*
* Get the insets for the preview. The default
* rotation is used for the preview, so we just use 0.
*/
int top = type.getTopInset(0);
int left = type.getLeftInset(0);
/*
* Loop through the piece and draw it's tiles onto the preview.
*/
for(int row = 0; row < dimension; row++) {
for(int col = 0; col < dimension; col++) {
if(type.isTile(col, row, 0)) {
drawTile(type, startX + ((col - left) * TILE_SIZE), startY + ((row - top) * TILE_SIZE), g);
}
}
}
}
}
/**
* Draws a tile onto the preview window.
* #param type The type of tile to draw.
* #param x The x coordinate of the tile.
* #param y The y coordinate of the tile.
* #param g The graphics object.
*/
private void drawTile(TileType type, int x, int y, Graphics g) {
/*
* Fill the entire tile with the base color.
*/
g.setColor(type.getBaseColor());
g.fillRect(x, y, TILE_SIZE, TILE_SIZE);
/*
* Fill the bottom and right edges of the tile with the dark shading color.
*/
g.setColor(type.getDarkColor());
g.fillRect(x, y + TILE_SIZE - SHADE_WIDTH, TILE_SIZE, SHADE_WIDTH);
g.fillRect(x + TILE_SIZE - SHADE_WIDTH, y, SHADE_WIDTH, TILE_SIZE);
/*
* Fill the top and left edges with the light shading. We draw a single line
* for each row or column rather than a rectangle so that we can draw a nice
* looking diagonal where the light and dark shading meet.
*/
g.setColor(type.getLightColor());
for(int i = 0; i < SHADE_WIDTH; i++) {
g.drawLine(x, y + i, x + TILE_SIZE - i - 1, y + i);
g.drawLine(x + i, y, x + i, y + TILE_SIZE - i - 1);
}
}
}
Related
I want to print a table with Java but my class that implements the Printable class print one page and when my table is big, break it into two pages and just prints the last page. I won't print one page if there is more pages print all of them.
this is my TablePrintable Class:
class TablePrintable implements Printable {
/** The table to print. */
private JTable table;
/** For quick reference to the table's header. */
private JTableHeader header;
/** For quick reference to the table's column model. */
private TableColumnModel colModel;
/** To save multiple calculations of total column width. */
private int totalColWidth;
/** The printing mode of this printable. */
private JTable.PrintMode printMode;
/** Provides the header text for the table. */
private MessageFormat headerFormat;
/** Provides the footer text for the table. */
private MessageFormat footerFormat;
/** The most recent page index asked to print. */
private int last = -1;
/** The next row to print. */
private int row = 0;
/** The next column to print. */
private int col = 0;
/** Used to store an area of the table to be printed. */
private final Rectangle clip = new Rectangle(0, 0, 0, 0);
/** Used to store an area of the table's header to be printed. */
private final Rectangle hclip = new Rectangle(0, 0, 0, 0);
/** Saves the creation of multiple rectangles. */
private final Rectangle tempRect = new Rectangle(0, 0, 0, 0);
/** Vertical space to leave between table and header/footer text. */
private static final int H_F_SPACE = 15;
/** Font size for the header text. */
private static final float HEADER_FONT_SIZE = 14.0f;
/** Font size for the footer text. */
private static final float FOOTER_FONT_SIZE = 10.0f;
/** The font to use in rendering header text. */
private Font headerFont;
/** The font to use in rendering footer text. */
private Font footerFont;
/**
* Create a new <code>TablePrintable</code> for the given
* <code>JTable</code>. Header and footer text can be specified using the
* two <code>MessageFormat</code> parameters. When called upon to provide a
* String, each format is given the current page number.
*
* #param table
* the table to print
* #param printMode
* the printing mode for this printable
* #param headerFormat
* a <code>MessageFormat</code> specifying the text to be used in
* printing a header, or null for none
* #param footerFormat
* a <code>MessageFormat</code> specifying the text to be used in
* printing a footer, or null for none
* #throws IllegalArgumentException
* if passed an invalid print mode
*/
public TablePrintable(JTable table, JTable.PrintMode printMode,
MessageFormat headerFormat,
MessageFormat footerFormat) {
this.table = table;
header = table.getTableHeader();
colModel = table.getColumnModel();
totalColWidth = colModel.getTotalColumnWidth();
if (header != null) {
// the header clip height can be set once since it's unchanging
hclip.height = header.getHeight();
}
this.printMode = printMode;
this.headerFormat = headerFormat;
this.footerFormat = footerFormat;
// derive the header and footer font from the table's font
headerFont = table.getFont().deriveFont(Font.BOLD, HEADER_FONT_SIZE);
footerFont = table.getFont().deriveFont(Font.PLAIN, FOOTER_FONT_SIZE);
}
/**
* Prints the specified page of the table into the given {#link Graphics}
* context, in the specified format.
*
* #param graphics
* the context into which the page is drawn
* #param pageFormat
* the size and orientation of the page being drawn
* #param pageIndex
* the zero based index of the page to be drawn
* #return PAGE_EXISTS if the page is rendered successfully, or NO_SUCH_PAGE
* if a non-existent page index is specified
* #throws PrinterException
* if an error causes printing to be aborted
*/
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex)
throws PrinterException {
// for easy access to these values
final int imgWidth = (int) pageFormat.getImageableWidth();
final int imgHeight = (int) pageFormat.getImageableHeight();
if (imgWidth <= 0) {
throw new PrinterException("Width of printable area is too small.");
}
if((table.getRowCount() * table.getRowHeight()) > imgHeight){
pageIndex++;
}
// to pass the page number when formatting the header and footer text
Object[] pageNumber = new Object[] { new Integer(pageIndex + 1) };
// fetch the formatted header text, if any
String headerText = null;
if (headerFormat != null) {
headerText = headerFormat.format(pageNumber);
}
// fetch the formatted footer text, if any
String footerText = null;
if (footerFormat != null) {
footerText = footerFormat.format(pageNumber);
}
// to store the bounds of the header and footer text
Rectangle2D hRect = null;
Rectangle2D fRect = null;
// the amount of vertical space needed for the header and footer text
int headerTextSpace = 0;
int footerTextSpace = 0;
// the amount of vertical space available for printing the table
int availableSpace = imgHeight;
System.out.println("available space: " + availableSpace);
System.out.println("the avail space // row Height => " +
(availableSpace/table.getRowHeight()));
// if there's header text, find out how much space is needed for it
// and subtract that from the available space
if (headerText != null) {
graphics.setFont(headerFont);
hRect = graphics.getFontMetrics().getStringBounds(headerText,
graphics);
headerTextSpace = (int) Math.ceil(hRect.getHeight());
availableSpace -= headerTextSpace + H_F_SPACE;
}
// if there's footer text, find out how much space is needed for it
// and subtract that from the available space
if (footerText != null) {
graphics.setFont(footerFont);
fRect = graphics.getFontMetrics().getStringBounds(footerText,
graphics);
footerTextSpace = (int) Math.ceil(fRect.getHeight());
availableSpace -= footerTextSpace;// TODO
}
if (availableSpace <= 0) {
throw new PrinterException("Height of printable area is too
small.");
}
// depending on the print mode, we may need a scale factor to
// fit the table's entire width on the page
double sf = 1.0D;
if (printMode == JTable.PrintMode.FIT_WIDTH && totalColWidth > imgWidth)
{
// if not, we would have thrown an acception previously
assert imgWidth > 0;
// it must be, according to the if-condition, since imgWidth > 0
assert totalColWidth > 1;
sf = (double) imgWidth / (double) totalColWidth;
}
// dictated by the previous two assertions
assert sf > 0;
// This is in a loop for two reasons:
// First, it allows us to catch up in case we're called starting
// with a non-zero pageIndex. Second, we know that we can be called
// for the same page multiple times. The condition of this while
// loop acts as a check, ensuring that we don't attempt to do the
// calculations again when we are called subsequent times for the
// same page.
while (last < pageIndex) {
// if we are finished all columns in all rows
if (row >= table.getRowCount() && col == 0) {
return NO_SUCH_PAGE;
}
// rather than multiplying every row and column by the scale factor
// in findNextClip, just pass a width and height that have already
// been divided by it
int scaledWidth = (int) (imgWidth / sf);
int scaledHeight = (int) ((availableSpace - hclip.height) / sf);
// calculate the area of the table to be printed for this page
findNextClip(scaledWidth, scaledHeight);
last++;
}
// translate into the co-ordinate system of the pageFormat
Graphics2D g2d = (Graphics2D) graphics;
g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
// to save and store the transform
AffineTransform oldTrans;
// if there's footer text, print it at the bottom of the imageable area
if (footerText != null) {
oldTrans = g2d.getTransform();
g2d.translate(0, imgHeight - footerTextSpace);
printFooterText(g2d, footerText, fRect, footerFont, imgWidth);
g2d.setTransform(oldTrans);
}
// if there's header text, print it at the top of the imageable area
// and then translate downwards
if (headerText != null) {
printHeaderText(g2d, headerText, hRect, headerFont, imgWidth);
g2d.translate(0, headerTextSpace + H_F_SPACE);
}
// constrain the table output to the available space
tempRect.x = 0;
tempRect.y = 0;
tempRect.width = imgWidth;
tempRect.height = availableSpace;
g2d.clip(tempRect);
// if we have a scale factor, scale the graphics object to fit
// the entire width
if (sf != 1.0D) {
g2d.scale(sf, sf);
// otherwise, ensure that the current portion of the table is
// centered horizontally
} else {
int diff = (imgWidth - clip.width) / 2;
g2d.translate(diff, 0);
}
// store the old transform and clip for later restoration
oldTrans = g2d.getTransform();
Shape oldClip = g2d.getClip();
// if there's a table header, print the current section and
// then translate downwards
if (header != null) {
hclip.x = clip.x;
hclip.width = clip.width;
g2d.translate(-hclip.x, 0);
g2d.clip(hclip);
header.print(g2d);
// restore the original transform and clip
g2d.setTransform(oldTrans);
g2d.setClip(oldClip);
// translate downwards
g2d.translate(0, hclip.height);
}
// print the current section of the table
g2d.translate(-clip.x, -clip.y);
g2d.clip(clip);
table.print(g2d);
// restore the original transform and clip
g2d.setTransform(oldTrans);
g2d.setClip(oldClip);
// draw a box around the table
g2d.setColor(Color.BLACK);
g2d.drawRect(0, 0, clip.width, hclip.height + clip.height);
return PAGE_EXISTS;
}
/**
* A helper method that encapsulates common code for rendering the header
* and footer text.
*
* #param g2d
* the graphics to draw into
* #param text
* the text to draw, non null
* #param rect
* the bounding rectangle for this text, as calculated at the
* given font, non null
* #param font
* the font to draw the text in, non null
* #param imgWidth
* the width of the area to draw into
*/
private void printHeaderText(Graphics2D g2d, String text, Rectangle2D rect,
Font font, int imgWidth) {
int tx;// TODO
// if the text is small enough to fit, center it
if (rect.getWidth() < imgWidth) {
tx = (int) ((imgWidth - rect.getWidth()) / 2);
// otherwise, if the table is LTR, ensure the left side of
// the text shows; the right can be clipped
} else if (table.getComponentOrientation().isLeftToRight()) {
tx = 0;
// otherwise, ensure the right side of the text shows
} else {
tx = -(int) (Math.ceil(rect.getWidth()) - imgWidth);
}
int ty = (int) Math.ceil(Math.abs(rect.getY()));
g2d.setColor(Color.BLACK);
g2d.setFont(MainUi.fLiner);
g2d.drawString(text, tx, ty);
}
private void printFooterText(Graphics2D g2d, String text, Rectangle2D rect,
Font font, int imgWidth) {
int tx;// TODO
// if the text is small enough to fit, center it
if (rect.getWidth() < imgWidth) {
tx = (int) ((imgWidth - rect.getWidth()) / 2);
// otherwise, if the table is LTR, ensure the left side of
// the text shows; the right can be clipped
} else if (table.getComponentOrientation().isLeftToRight()) {
tx = 0;
// otherwise, ensure the right side of the text shows
} else {
tx = -(int) (Math.ceil(rect.getWidth()) - imgWidth);
}
// int ty = (int) Math.ceil(Math.abs(rect.getY() + 30));
int ty = (int) Math.ceil(rect.getHeight());
g2d.setColor(Color.BLACK);
g2d.setFont(MainUi.ffLiner);
g2d.drawString(text, tx, ty-3);
}
/**
* Calculate the area of the table to be printed for the next page. This
* should only be called if there are rows and columns left to print.
*
* To avoid an infinite loop in printing, this will always put at least one
* cell on each page.
*
* #param pw
* the width of the area to print in
* #param ph
* the height of the area to print in
*/
private void findNextClip(int pw, int ph) {
final boolean ltr = table.getComponentOrientation().isLeftToRight();
// if we're ready to start a new set of rows
if (col == 0) {
if (ltr) {
// adjust clip to the left of the first column
clip.x = 0;
} else {
// adjust clip to the right of the first column
clip.x = totalColWidth;
}
// adjust clip to the top of the next set of rows
clip.y += clip.height;
// adjust clip width and height to be zero
clip.width = 0;
clip.height = 0;
// fit as many rows as possible, and at least one
int rowCount = table.getRowCount();
int rowHeight = table.getRowHeight(row);
do {
clip.height += rowHeight;
if (++row >= rowCount) {
break;
}
rowHeight = table.getRowHeight(row);
} while (clip.height + rowHeight <= ph);
}
// we can short-circuit for JTable.PrintMode.FIT_WIDTH since
// we'll always fit all columns on the page
if (printMode == JTable.PrintMode.FIT_WIDTH) {
clip.x = 0;
clip.width = totalColWidth;
return;
}
if (ltr) {
// adjust clip to the left of the next set of columns
clip.x += clip.width;
}
// adjust clip width to be zero
clip.width = 0;
// fit as many columns as possible, and at least one
int colCount = table.getColumnCount();
int colWidth = colModel.getColumn(col).getWidth();
do {
clip.width += colWidth;
if (!ltr) {
clip.x -= colWidth;
}
if (++col >= colCount) {
// reset col to 0 to indicate we're finished all columns
col = 0;
break;
}
colWidth = colModel.getColumn(col).getWidth();
} while (clip.width + colWidth <= pw);
}
}
Hello I have created excel sheet by using POI. I've added picture(jpg-file) in the next way:
Workbook wb = new HSSFWorkbook();
CreationHelper helper = wb.getCreationHelper();
//...
InputStream is = new FileInputStream("img.jpg");
byte[] bytes = IOUtils.toByteArray(is);
int picIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_JPEG);
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(5);
anchor.setRow1(5);
Picture pict = drawing.createPicture(anchor, picIdx);
pict.resize();
Now I want the picture to fit into that cell, but i don't want to change its aspect ratio. the scales i can put into resize are in respect to the cell, which obviously can have a different ratio. I tried to calculate the scales but the problem is, that I can't get or set the row height in pixel, only in pt and i can't compute the cells ratio either bc the i can't get width and height in the same unit... Any suggestions?
There is a Units class in POI, which provide convertion between pixel and point.
And here are some methods might be helpful to set cell's width and height.
1.Centimeters to Pixels
public static int cmToPx(double cm) {
return (int) Math.round(cm * 96 / 2.54D);
}
96 is my Monitor's DPI (check yours from dpilove)
and 1 inch = 2.54 centimeters
2.Centimeters to RowHeight
public static int cmToH(double cm) {
return (int) (Units.pixelToPoints(cmToPx(cm)) * 20); //POI's Units
}
Usage: sheet.setDefaultRowHeight(cmToH(1.0))
Reference: HSSFRow#getHeightInPoints
Set the height in "twips" or 1/20th of a point.
3.Centimeters to ColumnWidth
public static int cmToW(double cm) {
return (int) Math.round(((cmToPx(cm) - 5.0D) / 8 * 7 + 5) / 7 * 256);
}
Usage: sheet.setColumnWidth(cmToW(1.0))
Use (px - 5.0D) / 8 to convert from pixels to points in excel width.(When drag column's width in excel, pixels and points will show around your cursor)
Reference: HSSFSheet#setColumnWidth
Set the width (in units of 1/256th of a character width)
Excel uses the following formula (Section 3.3.1.12 of the OOXML spec):
// Excel width, not character width
width = Truncate([{Number of Visible Characters} * {Maximum Digit Width} + {5 pixel padding}]/{Maximum Digit Width} * 256) / 256
Using the Calibri font as an example, the maximum digit width of 11 point font size is 7 pixels (at 96 dpi). If you set a column width to be eight characters wide, e.g. setColumnWidth(columnIndex, 8*256), then the actual value of visible characters (the value shown in Excel) is derived from the following equation:
Truncate([numChars * 7 + 5] / 7 * 256) / 256 = 8;
Use XSSFClientAnchor to resize a picture to fill the cell and keep its ratio:
// set padding between picture and gridlines so gridlines would not covered by the picture
private static final double PADDING_SIZE = 10;
private static final int PADDING = Units.toEMU(PADDING_SIZE);
/**
* Draw Image inside specific cell
*
* #param wb workbook
* #param sheet sheet
* #param cellW cell width in pixels
* #param cellH cell height in pixels
* #param imgPath image path
* #param col the column (0 based) of the first cell.
* #param row the row (0 based) of the first cell.
* #param colSize the column size of cell
* #param rowSize the row size of cell
*/
public static void drawImageInCell(SXSSFWorkbook wb, SXSSFSheet sheet, int cellW, int cellH,
String imgPath, int col, int row, int colSize, int rowSize) throws IOException {
Path path = Paths.get(imgPath);
BufferedImage img = ImageIO.read(path.toFile());
int[] anchorArray = calCellAnchor(Units.pixelToPoints(cellW), Units.pixelToPoints(cellH),
img.getWidth(), img.getHeight());
XSSFClientAnchor anchor = new XSSFClientAnchor(anchorArray[0], anchorArray[1], anchorArray[2],
anchorArray[3], (short) col, row, (short) (col + colSize), row + rowSize);
int index = wb.addPicture(Files.readAllBytes(path), XSSFWorkbook.PICTURE_TYPE_JPEG);
sheet.createDrawingPatriarch().createPicture(anchor, index);
}
/**
* calculate POI cell anchor
*
* #param cellX cell width in excel points
* #param cellY cell height in excel points
* #param imgX image width
* #param imgY image height
*/
public static int[] calCellAnchor(double cellX, double cellY, int imgX, int imgY) {
// assume Y has fixed padding first
return calCoordinate(true, cellX, cellY, imgX, imgY);
}
/**
* calculate cell coordinate
*
* #param fixTop is Y has fixed padding
*/
private static int[] calCoordinate(boolean fixTop, double cellX, double cellY, int imgX, int imgY) {
double ratio = ((double) imgX) / imgY;
int x = (int) Math.round(Units.toEMU(cellY - 2 * PADDING_SIZE) * ratio);
x = (Units.toEMU(cellX) - x) / 2;
if (x < PADDING) {
return calCoordinate(false, cellY, cellX, imgY, imgX);
}
return calDirection(fixTop, x);
}
/**
* calculate X's direction
*
* #param fixTop is Y has fixed padding
* #param x X's padding
*/
private static int[] calDirection(boolean fixTop, int x) {
if (fixTop) {
return new int[] { x, PADDING, -x, -PADDING };
} else {
return new int[] { PADDING, x, -PADDING, -x };
}
}
I am using Base64 image data and I do it like this, for me it adds at given col/row and resizes it properly, also I dont want to to fit the cell it can axpand to whatever to right and bottom:
byte[] imageBase64Data = base64DataString.getBytes();
byte[] imageRawData = Base64.getDecoder().decode(imageBase64Data);
int imgWidth = 1920; // only initial if not known
int imgHeight = 1080; // only initial if not known
try {
BufferedImage img = ImageIO.read(new ByteArrayInputStream(imageRawData));
imgWidth = img.getWidth();
imgHeight = img.getHeight();
} catch (IOException e) {
e.printStackTrace();
}
int pictureIdx = workbook.addPicture(imageRawData, Workbook.PICTURE_TYPE_PNG);
CreationHelper helper = workbook.getCreationHelper();
Drawing drawing = sheet.createDrawingPatriarch();
ClientAnchor anchor = helper.createClientAnchor();
anchor.setCol1(desiredCol);
anchor.setRow1(desiredRow);
Picture picture = drawing.createPicture(anchor, pictureIdx);
picture.resize(0.7 * imgWidth / XSSFShape.PIXEL_DPI, 5 * imgHeight / XSSFShape.PIXEL_DPI);
I'm trying to find different ways of centering text within a main menu that I'm trying to create, but all the ways that I've tried centers the string from the first letter. Is there any way of determining the length of the string passed in and then work out the center from that?
If you're using a JLabel, overload the constructor using a center attribute. example:
label = new JLabel("insert text here");
to
label = new JLabel("insert text here", SwingConstants.CENTER);
I wrote this a while back.
/**
* This method centers a <code>String</code> in
* a bounding <code>Rectangle</code>.
* #param g - The <code>Graphics</code> instance.
* #param r - The bounding <code>Rectangle</code>.
* #param s - The <code>String</code> to center in the
* bounding rectangle.
* #param font - The display font of the <code>String</code>
*
* #see java.awt.Graphics
* #see java.awt.Rectangle
* #see java.lang.String
*/
public void centerString(Graphics g, Rectangle r, String s,
Font font) {
FontRenderContext frc =
new FontRenderContext(null, true, true);
Rectangle2D r2D = font.getStringBounds(s, frc);
int rWidth = (int) Math.round(r2D.getWidth());
int rHeight = (int) Math.round(r2D.getHeight());
int rX = (int) Math.round(r2D.getX());
int rY = (int) Math.round(r2D.getY());
int a = (r.width / 2) - (rWidth / 2) - rX;
int b = (r.height / 2) - (rHeight / 2) - rY;
g.setFont(font);
g.drawString(s, r.x + a, r.y + b);
}
I've been playing around with Slick2D for Java and I managed to get it to display maps and have my character sprite move around.
I've tried to implement a camera that follows the player so that the map scrolls. While the map is scrolling, that characters move speed is faster than it should be (possibly due to the camera srolling it as well as it moving with the keys)
I'm stumped on how to solve it though
The camera code is something i found on the slick forums, and modified slightly to draw each layer seperatly, modifying both drawmap methods to add the layer in. I would ask on the forums but they seem dead.
This is the camera code
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package engine;
/**
*
* #author Ceri
*/
import java.awt.geom.Point2D;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.tiled.TiledMap;
public class Camera {
/**
* the map used for our scene
*/
protected TiledMap map;
/**
* the number of tiles in x-direction (width)
*/
protected int numTilesX;
/**
* the number of tiles in y-direction (height)
*/
protected int numTilesY;
/**
* the height of the map in pixel
*/
protected int mapHeight;
/**
* the width of the map in pixel
*/
protected int mapWidth;
/**
* the width of one tile of the map in pixel
*/
protected int tileWidth;
/**
* the height of one tile of the map in pixel
*/
protected int tileHeight;
/**
* the GameContainer, used for getting the size of the GameCanvas
*/
protected GameContainer gc;
/**
* the x-position of our "camera" in pixel
*/
protected float cameraX;
/**
* the y-position of our "camera" in pixel
*/
protected float cameraY;
protected Point2D.Float currentCenterPoint = new Point2D.Float(0, 0);
/**
* Create a new camera
*
* #param gc the GameContainer, used for getting the size of the GameCanvas
* #param map the TiledMap used for the current scene
*/
public Camera(GameContainer gc, TiledMap map) {
this.map = map;
this.numTilesX = map.getWidth();
this.numTilesY = map.getHeight();
this.tileWidth = map.getTileWidth();
this.tileHeight = map.getTileHeight();
this.mapWidth = this.numTilesX * this.tileWidth;
this.mapHeight = this.numTilesY * this.tileHeight;
this.gc = gc;
}
/**
* "locks" the camera on the given coordinates. The camera tries to keep the
* location in it's center.
*
* #param x the real x-coordinate (in pixel) which should be centered on the
* screen
* #param y the real y-coordinate (in pixel) which should be centered on the
* screen
* #return
*/
public Point2D.Float centerOn(float x, float y) {
//try to set the given position as center of the camera by default
cameraX = x - gc.getWidth() / 2;
cameraY = y - gc.getHeight() / 2;
//if the camera is at the right or left edge lock it to prevent a black bar
if (cameraX < 0) {
cameraX = 0;
}
if (cameraX + gc.getWidth() > mapWidth) {
cameraX = mapWidth - gc.getWidth();
}
//if the camera is at the top or bottom edge lock it to prevent a black bar
if (cameraY < 0) {
cameraY = 0;
}
if (cameraY + gc.getHeight() > mapHeight) {
cameraY = mapHeight - gc.getHeight();
}
currentCenterPoint.setLocation(cameraX, cameraY);
return currentCenterPoint;
}
/**
* "locks" the camera on the center of the given Rectangle. The camera tries
* to keep the location in it's center.
*
* #param x the x-coordinate (in pixel) of the top-left corner of the
* rectangle
* #param y the y-coordinate (in pixel) of the top-left corner of the
* rectangle
* #param height the height (in pixel) of the rectangle
* #param width the width (in pixel) of the rectangle
*/
public void centerOn(float x, float y, float height, float width) {
this.centerOn(x + width / 2, y + height / 2);
}
/**
* "locks the camera on the center of the given Shape. The camera tries to
* keep the location in it's center.
*
* #param shape the Shape which should be centered on the screen
*/
public void centerOn(Shape shape) {
this.centerOn(shape.getCenterX(), shape.getCenterY());
}
/**
* draws the part of the map which is currently focussed by the camera on
* the screen
*/
public void drawMap(int layer) {
this.drawMap(0, 0, layer);
}
/**
* draws the part of the map which is currently focussed by the camera on
* the screen.<br>
* You need to draw something over the offset, to prevent the edge of the
* map to be displayed below it<br>
* Has to be called before Camera.translateGraphics() !
*
* #param offsetX the x-coordinate (in pixel) where the camera should start
* drawing the map at
* #param offsetY the y-coordinate (in pixel) where the camera should start
* drawing the map at
*/
public void drawMap(int offsetX, int offsetY, int layer) {
//calculate the offset to the next tile (needed by TiledMap.render())
int tileOffsetX = (int) -(cameraX % tileWidth);
int tileOffsetY = (int) -(cameraY % tileHeight);
//calculate the index of the leftmost tile that is being displayed
int tileIndexX = (int) (cameraX / tileWidth);
int tileIndexY = (int) (cameraY / tileHeight);
//finally draw the section of the map on the screen
map.render(
tileOffsetX + offsetX,
tileOffsetY + offsetY,
tileIndexX,
tileIndexY,
(gc.getWidth() - tileOffsetX) / tileWidth + 1,
(gc.getHeight() - tileOffsetY) / tileHeight + 1, layer, false);
}
/**
* Translates the Graphics-context to the coordinates of the map - now
* everything can be drawn with it's NATURAL coordinates.
*/
public void translateGraphics() {
gc.getGraphics().translate(-cameraX, -cameraY);
}
/**
* Reverses the Graphics-translation of Camera.translatesGraphics(). Call
* this before drawing HUD-elements or the like
*/
public void untranslateGraphics() {
gc.getGraphics().translate(cameraX, cameraY);
}
}
and this is how its being called
In the engine class
public void render(GameContainer gc, Graphics g) throws SlickException {
camera = new Camera(gc, world.map);
camera.centerOn(player.getX(), player.getY());
camera.drawMap(0);
camera.drawMap(1);
player.draw();
camera.drawMap(2);
}
This is how the player class is
public Player(MapClass m) throws SlickException {
map = m;
Image[] movementUp = {new Image("Images/Player/u1.png"), new Image("Images/Player/u2.png"), new Image("Images/Player/u3.png"), new Image("Images/Player/u4.png")};
Image[] movementDown = {new Image("Images/Player/d1.png"), new Image("Images/Player/d2.png"), new Image("Images/Player/d3.png"), new Image("Images/Player/d4.png")};
Image[] movementLeft = {new Image("Images/Player/l1.png"), new Image("Images/Player/l2.png"), new Image("Images/Player/l3.png"), new Image("Images/Player/l4.png")};
Image[] movementRight = {new Image("Images/Player/r1.png"), new Image("Images/Player/r2.png"), new Image("Images/Player/r3.png"), new Image("Images/Player/r4.png")};
int[] duration = {100, 100, 100, 100};
up = new Animation(movementUp, duration, false);
down = new Animation(movementDown, duration, false);
left = new Animation(movementLeft, duration, false);
right = new Animation(movementRight, duration, false);
// Original orientation of the sprite. It will look right.
sprite = right;
}
public void update(GameContainer container, int delta) throws SlickException {
Input input = container.getInput();
if (input.isKeyDown(Input.KEY_UP)) {
sprite = up;
sprite.update(delta);
// The lower the delta the slowest the sprite will animate.
if (!map.isBlocked(x, y - delta * 0.1f))
y -= delta * 0.1f;
} else if (input.isKeyDown(Input.KEY_DOWN)) {
sprite = down;
sprite.update(delta);
if (!map.isBlocked(x, y + 16 + delta * 0.1f))
y += delta * 0.1f;
} else if (input.isKeyDown(Input.KEY_LEFT)) {
sprite = left;
sprite.update(delta);
if (!map.isBlocked(x - delta * 0.1f, y))
x -= delta * 0.1f;
} else if (input.isKeyDown(Input.KEY_RIGHT)) {
sprite = right;
sprite.update(delta);
if (!map.isBlocked(x + 16 + delta * 0.1f, y))
x += delta * 0.1f;
}
}
public void draw() {
sprite.draw(x, y);
}
Fixed it. Moved the map draw out of the camera class into the map class. used the camera x/y created in the camera class in the map and player class
I had been through this link1 link2 for an answer, but was not helpful.
Because
frame.setVisible(false);
is giving below exception,
Exception in thread "main" java.lang.NullPointerException
at Simulation.drawOcean(Simulation.java:72)
at Simulation.main(Simulation.java:191)
Application has below 2 java files.
Simulation class launches GUI.
After running Simulation.java with default command line parameters, Frame does not get close, despite finite while loop.
I could not close the Frame by clicking close button(top right - red), after the simulation is done.
Do i need to set some property for Frame?
Please help me!!!
/* Simulation.java */
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.util.Random;
/* DO NOT CHANGE THIS FILE (except as noted). */
/* (You may wish to make temporary changes or insert println() statements) */
/* while testing your code. When you're finished testing and debugging, */
/* though, make sure your code works with the original version of this file */
/**
* The Simulation class is a program that runs and animates a simulation of
* Sharks and Fish.
*
* The Simulation program takes up to four parameters. The first two specify
* the width and height of the ocean. The third parameter specifies the value
* of starveTIme. For example, if you run
*
* java Simulation 25 25 1
*
* then Simulation will animate a 25x25 ocean with a starveTime of 1. If you
* run "java Simulation" with no parameters, by default Simulation will animate
* a 50x25 ocean with a starveTime of 3. With some choices of parameters,
* the ocean quickly dies out; with others;, it teems forever.
*
* #author mohet01
*
*/
public class Simulation {
/**
* The constant cellSize determines the size of each cell on the screen
* during animation. (You may change this if you wish).
*/
private static final int cellSize = 4;
/**
* Default parameters. (You may change this of you wish).
*/
private static int i = 50; //Default ocean width
private static int j = 25; //Default ocean height
private static int starveTime = 3; //Default shark starvation time
/**
* drawOcean() adds cell contents as part of graphics
*/
private static void drawOcean(Graphics graphics, Ocean ocean){
if(ocean != null){
int width = ocean.width();
int height = ocean.height();
for(int row = 0; row < height; row++){
for(int col = 0; col < width; col++){
int contents = ocean.cellContents(row, col);
if(contents == Ocean.SHARK){
//Draw a red Shark
graphics.setColor(Color.red);
graphics.fillRect(row*cellSize, col*cellSize, cellSize, cellSize);
}else if(contents == Ocean.FISH){
// Draw a green fish
graphics.setColor(Color.green);
graphics.fillRect(row * cellSize, col * cellSize, cellSize, cellSize);
}else{
//Clear the rectangle
graphics.clearRect(row, col, cellSize, cellSize);
}
}
}
}
}
/**
* main() reads the parameters and performs the simulation and animation.
* #param args
* #throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Ocean sea;
/**
* Read the input parameters
*/
if(args.length >0){
try{
i = Integer.parseInt(args[0]);
}catch(NumberFormatException e){
System.out.println("First argument to Simulation is not a number.");
}
}
if(args.length > 1){
try{
j = Integer.parseInt(args[1]);
}catch(NumberFormatException e){
System.out.println("Second argument to Simulation is not a number");
}
}
if(args.length > 2){
try{
starveTime = Integer.parseInt(args[2]);
}catch(NumberFormatException e){
System.out.println("Third argument to Simulation is not a number");
}
}
/**
* Create a window on your screen
*/
Frame frame = new Frame("Sharks and Fish");
frame.setSize(i*cellSize + 10, j*cellSize + 30);
frame.setVisible(true);
/**
* Create a "Canvas" we can draw upon; attach it to the window
*/
Canvas canvas = new Canvas();
canvas.setBackground(Color.white);
canvas.setSize(i*cellSize, j*cellSize);
frame.add(canvas);
Graphics graphics = canvas.getGraphics();
/**
* Create the initial ocean.
*/
sea = new Ocean(i, j, starveTime);
/**
* Visit each cell (in a roundabout order); randomnly place a fish, shark,
* or nothing in each.
*/
Random random = new Random(0);
int x = 0;
int y = 0;
for(int row = 0;row < j; row++){
//This will visit every x-coordinate once.
x = (x + 78887) %j;
if((x & 8) == 0){
for(int col = 0; col < i; col++){
//This will visit every y coordinate once.
y = (y+78887)%i;
if((y & 8) == 0){
int r = random.nextInt();
if(r < 0){
//50% of cells start with fish
//x - width, y - height
sea.addFish(x, y);
}else if(r > 1500000000){
//~15% of cells start with sharks
sea.addShark(x, y);
}
}
}
}
}
/**
* Perform timesteps forever
*/
int timeLeft = 20;
while (timeLeft > 0) {
// Wait one second (1000 milliseconds)
Thread.sleep(1000);
// Draw the current ocean
drawOcean(graphics, sea);
// For fun, you might wish to change the delay in the next line.
// If you make it too short, though, the graphics won't work properly.
// Simulate a timestep
sea = sea.timeStep();
timeLeft--;
}
}
}
/* Ocean.java */
/**
* The Ocean class defines an object that models an ocean full of sharks and
* fish. Descriptions of the methods you must implements appear below. They
* include a constructor of the form
*
* public Ocean(int i, int j, int starveTime);
*
* that creates an empty ocean having width i and height j, in which sharks
* starve after starveTime timesteps.
*
* See the README file accompanying this project for additional details.
*
* #author mohet01
*
*/
public class Ocean {
/**
* Do not rename these constants. WARNING: if you change the numbers, you
* will need to recompile Test4.java. Failure to do so will give you a very
* hard-to-find bug.
*/
public final static int EMPTY = 1;
public final static int SHARK = 2;
public final static int FISH = 3;
/**
* Define any variables associated with an Ocean object here. These
* variables MUST be private.
*
*/
private final static int UNKNOWN = -1; // for unknown return type
private int width;
private int height;
private int[][] oceanMatrix;
//TODO space optimization on below matrix
private int[][] sharkHungerLevelMatrix;
private int starveTime;
/**
* The following methods are required for Part I.
*
*/
/**
* Constructor that creates an empty ocean having width i and
* height j, in which sharks starve until after starveTime timesteps.
*
* #param width(i)
* is the width of the ocean.
* #param height(j)
* is the height of the ocean.
* #param starveTime
* is the number of timeSteps sharks survive without food.
*/
public Ocean(int i, int j, int starveTime) {
this.width = i;
this.height = j;
this.oceanMatrix = new int[j][i];
this.sharkHungerLevelMatrix = new int[j][i];
this.starveTime = starveTime;
for (int row = 0; row < j; row++) {
for (int col = 0; col < i; col++) {
oceanMatrix[row][col] = EMPTY;
}
}
for (int row = 0; row < j; row++) {
for (int col = 0; col < i; col++) {
sharkHungerLevelMatrix[row][col] = EMPTY;
}
}
}
/**
* width() returns the width of an ocean Object.
*
* #return the width of the ocean.
*
*/
public int width() {
return this.width;
}
/**
* height() returns the height of an Ocean object.
*
* #return the height of the Ocean.
*/
public int height() {
return this.height;
}
/**
* starveTime() returns the number of timesteps sharks survive without food.
*
* #return the number of timesteps sharks survive without food.
*/
public int starveTime() {
return starveTime;
}
/**
* addFish() places a fish in cell (x,y) if the cell is empty. If the cell
* is already occupied, leave the cell as it is.
*
* #param x
* is the x-coordinate of the cell to place a fish in.
* #param y
* is the y-coordinate of the cell to place a fish in.
*/
public void addFish(int x, int y) {
if (oceanMatrix[x][y] == EMPTY) {
oceanMatrix[x][y] = FISH;
}
}
/**
* addShark() (with two parameters) places a newborn shark in cell (x, y) if
* the cell is empty. A "newborn" shark is equivalent to a shark that has
* just eaten. If the cell is already occupied, leave the cell as it is.
*
* #param x
* is the x-coordinate of the cell to place a shark in.
* #param y
* is the y-coordinate of the cell to place a shark in.
*/
public void addShark(int x, int y) {
if (oceanMatrix[x][y] == EMPTY) {
oceanMatrix[x][y] = SHARK;
}
}
/**
* cellContents() returns EMPTY is cell (x,y) is empty, FISH if it contains
* a fish, and SHARK if it contains a shark.
*
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
*/
public int cellContents(int x, int y) {
return oceanMatrix[x][y];
}
/**
* isFish() checks for the existence of fish in that cell.
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isFish(int x, int y){
return (this.oceanMatrix[x][y] == Ocean.FISH);
}
/**
* isShark() checks for the existence of shark in that cell.
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isShark(int x, int y){
return (this.oceanMatrix[x][y] == Ocean.SHARK);
}
/**
* isSharkStarving() checks the hunger level of shark, if reached to starveTime level
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return the boolean value
*/
private boolean isSharkStarving(int x, int y){
return (this.sharkHungerLevelMatrix[x][y] == (this.starveTime+1));
}
/**
* checkFish() checks the existence of atleast one fish
* surrounding shark cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns true on atleast one fish exist otherwise false
*
*/
private boolean checkFish(int x, int y){
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isFish(mod(i,this.height), mod(j,this.width))){
return true;
}
}
}
return false;
}
/**
* countShark() counts the number of sharks surrounding queried cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns number of sharks surrounding fish cell
*/
private int countShark(int x, int y){
int neighbourSharkCount = 0;
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isShark(mod(i,this.height), mod(j,this.width))){
neighbourSharkCount++;
}
} // end inner for loop
}//end outer for loop
return neighbourSharkCount;
}
/**
* countFish() counts the number of fish surrounding queried cell
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
* #return returns number of sharks surrounding queried cell
*/
private int countFish(int x, int y){
int neighbourFishCount = 0;
for(int i = x-1;i <= x+1; i++){
for(int j = y-1; j <= y+1; j++){
if(this.isFish(mod(i,this.height), mod(j,this.width))){
neighbourFishCount++;
}
} // end inner for loop
}//end outer for loop
return neighbourFishCount;
}
/**
* mod() performs the modulo operation using euclidean divison
*
* #param n
* is the numerator
* #param d
* is the denominator
* #return the remainder
*/
private int mod(int n, int d) {
if (n >= 0)
return n % d;
else
return d + ~(~n % d);
}
/**
* timeStep() performs a simulation timestep as described in README.
*
* #return an ocean representing the elapse of one timestep.
*/
public Ocean timeStep() {
Ocean sea = new Ocean(width, height, starveTime);
for (int row = 0; row < this.height; row++) {
for (int col = 0; col < this.width; col++) {
switch(this.oceanMatrix[row][col]){
case Ocean.SHARK:
boolean gotTheFish = false;
//Check all the 8 neighbors of a Shark Cell for fish
if(this.checkFish(row,col)){
gotTheFish = true;
}
//Updating Shark Cell
if(gotTheFish){
/*
* 1) If a cell contains a shark, and any of its neighbors is a fish, then the
* shark eats during the time step, and it remains in the cell at the end of the
* time step. (We may have multiple sharks sharing the same fish. This is fine;
* they all get enough to eat.)
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // for next time step
}else{
/*
* 2) If a cell contains a shark, and none of its neighbors is a fish, it gets
* hungrier during the time step. If this time step is the (starveTime + 1)th
* time step the shark has gone through without eating, then the shark dies
* (disappears). Otherwise, it remains in the cell.
*/
this.sharkHungerLevelMatrix[row][col]++;
if(this.isSharkStarving(row,col)){
this.oceanMatrix[row][col] = Ocean.EMPTY; // for this time step
this.sharkHungerLevelMatrix[row][col] = Ocean.EMPTY; // for this time step
}
sea.sharkHungerLevelMatrix[row][col] = this.sharkHungerLevelMatrix[row][col]; // for next time step
sea.oceanMatrix[row][col] = this.oceanMatrix[row][col]; // for next time step
}
break;
case Ocean.FISH:
int neighbourSharkCount=0;
//Check all the 8 neighbors of a Fish cell to count for sharks
neighbourSharkCount=countShark(row,col);
//Updating fish cell for current & next time step
if(neighbourSharkCount ==1){
/*
* 4) If a cell contains a fish, and one of its neighbors is a shark, then the
* fish is eaten by a shark, and therefore disappears.
*/
this.oceanMatrix[row][col] = Ocean.EMPTY; //fish disappears this time step
}
else if(neighbourSharkCount > 1){
/*
* 5) If a cell contains a fish, and two or more of its neighbors are sharks, then
* a new shark is born in that cell. Sharks are well-fed at birth; _after_ they
* are born, they can survive an additional starveTime time steps without eating.
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // new shark for next time step
}
else if(neighbourSharkCount < 1){
/*
* 3) If a cell contains a fish, and all of its neighbors are either empty or are
* other fish, then the fish stays where it is.
*/
sea.oceanMatrix[row][col] = FISH; //for next time step
}
break;
case Ocean.EMPTY:
int fishCount=0;
int sharkCount=0;
//Check all the 8 neighbors of an Empty cell to count sharks and Fish
fishCount = this.countFish(row,col);
sharkCount = this.countShark(row, col);
//Update Empty Cell for current & next time step.
/* (no need to handle this case)
* 6) If a cell is empty, and fewer than two of its neighbors are fish, then the
* cell remains empty.
*/
if((fishCount >= 2) && (sharkCount <=1)){
/*
* 7) If a cell is empty, at least two of its neighbors are fish, and at most one
* of its neighbors is a shark, then a new fish is born in that cell.
*/
this.oceanMatrix[row][col] = FISH;// for current time step
sea.oceanMatrix[row][col] = FISH; //for next time step
}else if((fishCount >= 2) && (sharkCount >= 2)){
/*
* 8) If a cell is empty, at least two of its neighbors are fish, and at least two
* of its neighbors are sharks, then a new shark is born in that cell. (The new
* shark is well-fed at birth, even though it hasn’t eaten a fish yet.)
*/
sea.oceanMatrix[row][col] = Ocean.SHARK; // for next time step
}
break;
}
}//end inner for loop
}//end outer for loop
return sea;
}
/**
* The following method is required for Part II.
*
*
*/
/**
* addShark() (with three parameters) places a shark in cell (x, y) if the
* cell is empty. The shark's hunger is represented by the third parameter.
* If the cell is already occupied, leave the cell as it is, You will need
* this method to help convert run-length encodings to Oceans.
*
* #param x
* is the x-coordinate of the cell to place a shark in.
* #param y
* is the y-coordinate of the cell to place a shark in.
* #param feeding
* is an integer that indicates the shark's hunger. You may
* encode it any way you want; for instance, "feeding" may be the
* last timestep the shark was fed, or the amount of time that
* has passed since the shark was last fed, or the amount of time
* left before the shark will starve. It's upto you, but be
* consistent.
*/
public void addShark(int x, int y, int feeding) {
this.oceanMatrix[x][y] = Ocean.SHARK;
this.sharkHungerLevelMatrix[x][y] = feeding;
}
/**
* The following method is required for Part III.
*/
/**
* sharkFeeding() returns an integer that indicates the hunger of the shark
* in cell (x, y), using the same "feeding" representation as the parameter
* to addShark() described above. If cell (x, y) does not contain a shark,
* then its return value is undefined--that is, anything you want. Normally,
* this method should not be called if cell (x, y) does not contain a shark.
* You will need this method to help convert Oceans to run-length encodings.
*
* #param x
* is the x-coordinate of the cell whose contents are queried.
* #param y
* is the y-coordinate of the cell whose contents are queried.
*
*/
public int sharkFeeding(int x, int y) {
if(this.isShark(x, y)){
return this.sharkHungerLevelMatrix[x][y];
}
return Ocean.UNKNOWN;
}
}
While this is not a Swing program, you can substitute JFrame for Frame to leverage EXIT_ON_CLOSE.
JFrame frame = new JFrame("Sharks and Fish");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
The AWT approach is to add a WindowListener.
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
Have you tried?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);