Using swing and awt i've created a grid. The user can click over any empty cell
of the grid, marking it as a red cell. The grid is composed by 20 x 20 cells, 32 pixels each.
When the user clicks over a cell, i get the x and y coordinates of the mouse click and i perform the following calculation to find out which is the selected
cell:
int mouseX = e.getX();
int mouseY = e.getY();
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
The problem is that row and col get inaccurate (wrong) when i click near the edges of a cell (right border or bottom border), resulting in the marking of the next cell (cell to the right or cell to the bottom) and not in the marking of the correct one that i'm clicking over.
The more i get closest to the right/bottom borders of the grid, the more the accuracy is bad.
This is how i draw the grid:
public class MainPanel extends JPanel {
// reference to the model
private Model model;
public MainPanel() {
setPreferredSize(new Dimension(660, 660));
// retrieve the model
model = Controller.getController().getModel();
// draw
repaint();
// listen to mouse clicks
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);
// get the row and column clicked
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
if(row > Model.BOARD_SIZE - 1 || col > Model.BOARD_SIZE - 1) { // avoid out of bounds
return;
}
System.out.println("row: " + row + " col: " + col);
Controller.getController().getModel().setTarget(col, row);
repaint();
}
});
}
/**
* Custom painting codes on this JPanel
* Called by repaint()
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // fills background
setBackground(Color.WHITE); // sets background color
// draw the tiles
Node[][] nodes = model.getBoard();
for(int i = 0; i < Model.BOARD_SIZE; i++) {
for(int j = 0; j < Model.BOARD_SIZE; j++) {
if(nodes[i][j].getNodeType() == NodeType.OBSTACLE) {
g.setColor(Color.BLACK);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else if(nodes[i][j].getNodeType() == NodeType.SOURCE) {
g.setColor(Color.GREEN);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else if(nodes[i][j].getNodeType() == NodeType.TARGET) {
g.setColor(Color.RED);
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
else {
g.setColor(Color.BLACK);
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
}
}
}
}
}
Link to the runnable:
https://www.dropbox.com/s/bqoimipp7i1f39s/GridExample.jar?dl=0
Your paint code is wrong, basically...
g.drawRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
is increasing the size of each cell by a factor of the row/cell been drawn, for example...
The green line is calculated by using g.drawRect(0, 0, BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE);, which should be the visible area of your grid, but you're drawing beyond it.
Instead, if I use...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
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.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new MainPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class MainPanel extends JPanel {
public static final int NODE_SIZE = 32;
public static final int BOARD_SIZE = 8;
private int row, col = -1;
public MainPanel() {
// listen to mouse clicks
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
System.out.println("mouseX: " + mouseX + " mouseY: " + mouseY);
// get the row and column clicked
int row = mouseY / NODE_SIZE;
int col = mouseX / NODE_SIZE;
if (row > BOARD_SIZE - 1 || col > BOARD_SIZE - 1) { // avoid out of bounds
return;
}
System.out.println("row: " + row + " col: " + col);
repaint();
}
});
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
row = mouseY / NODE_SIZE;
col = mouseX / NODE_SIZE;
repaint();
}
});
}
#Override
public Dimension getPreferredSize() {
return new Dimension(BOARD_SIZE * NODE_SIZE, BOARD_SIZE * NODE_SIZE);
}
/**
* Custom painting codes on this JPanel Called by repaint()
*/
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g); // fills background
setBackground(Color.WHITE); // sets background color
g.setColor(Color.GREEN);
for (int i = 0; i < BOARD_SIZE; i++) {
for (int j = 0; j < BOARD_SIZE; j++) {
if (row == j && col == i) {
g.setColor(Color.RED);
g.fillRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
}
g.setColor(Color.BLACK);
g.drawRect(NODE_SIZE * i, NODE_SIZE * j, NODE_SIZE, NODE_SIZE);
}
}
}
}
}
It becomes decidedly more accurate..
Another idea might be to use Rectangle to define each cell of the grid, that way you could just use Rectangle#contains to test if the mouse is within any given cell bounds...as an idea
Seeing this code:
g.fillRect(i + Model.NODE_SIZE * i, j + Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
In combination with this code:
int row = mouseY / Model.NODE_SIZE;
int col = mouseX / Model.NODE_SIZE;
is suspicious, your drawing your rectangles on screen with a size of i + Model.NODE_SIZE * i - so the size of rectangles on screen are offset by 1 for every preceding rectangle. This offset would compound making your underlying "detection" of the rectangle you selected slowly get worse the further bottom right on the screen you click.
I suspect if you change your code to read
g.fillRect(Model.NODE_SIZE * i, Model.NODE_SIZE * j, Model.NODE_SIZE, Model.NODE_SIZE);
It will work as intended.
Related
I'm a newbie in programming and I need some lights and help.I'm developing a game in which two players have to play with tokens (say red and blue) by placing them in cells (75x75 grid). The goal is to "capture" opponent's tokens by surrounding them. (See the image, which is the actual game output, the surrounding is drawn by hand)
To do so, I need to make the tokens "listen" to neighborhood, meaning other cells in the grid. A token has to check for itself in the grid(what is its position in the grid) and check of there is another token close to it, checks it color (blue or red) then,a in certain conditions, trigger the capturing mechanism
[![Game board with tokens][1]][1]
What I have done, technically:
Created the grid ( Grid/board is a 2 dimensional array of Token objects.)
The token (which is an enumeration: EMPTY, BLUE_TOKEN, RED_TOKEN.
A currentPlayer is also a Token .
When it's the user turn, they select an empty cell at which they point. They place the currentPlayer into the grid/board at cell rowSelected, colSelected then repaint the canvas with the newly added cell in the grid/board.
Now i'm stuck on how to make the tokens listen the next cell surrounding them in order to see if there is an opponent or an ally.
PS: I've posted the same here, got downgraded because i didn't respect rules (ignorant I was)
Here is my code:
import javax.swing.JFrame;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
public class Phagocyte extends JFrame {
public static final int ROWS = 75;
public static final int COLS = 75;
public static final int CELL_SIZE = 18;
public static final int CANVAS_WIDTH = CELL_SIZE * COLS;
public static final int CANVAS_HEIGHT = CELL_SIZE * ROWS;
public static final int GRID_WIDTH = 8;
public static final int GRID_WIDHT_HALF = GRID_WIDTH / 2;
// Symbols (Blue token/Red Token) are displayed inside a cell with padding from borders
public static final int CELL_PADDING = CELL_SIZE / 5;
public static final int SYMBOL_SIZE = CELL_SIZE - CELL_PADDING * 2;
public static final int SYMBOL_STROKE_WIDTH = 3;
//This represent the various states of the game
public enum GameState {
PLAYING, DRAW, BLUE_TOKEN_WON, RED_TOKEN_WON //Haven't created a scenario yet
}
private GameState currentState; // The current state of the game
//This represent the Tokens and cell contents
public enum Token {
EMPTY, BLUE_TOKEN, RED_TOKEN
}
private Token currentPlayer; // The current player (whether red or blue)
private Token[][] board ; // This is the game board of cells (ROWS by COLS)
private DrawCanvas canvas;
private JLabel statusBar;
/**The components of the the game and the GUI are setup here */
public Phagocyte() {
canvas = new DrawCanvas();
canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
canvas.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
int mouseX = e.getX();
int mouseY = e.getY();
// Here to get the row and column that is clicked
int rowSelected = mouseY / CELL_SIZE;
int colSelected = mouseX / CELL_SIZE;
if (currentState == GameState.PLAYING) {
if (rowSelected >= 0 && rowSelected < ROWS && colSelected >= 0
&& colSelected < COLS && board[rowSelected][colSelected] == TOKEN.EMPTY) {
board[rowSelected][colSelected] = currentPlayer;
updateGame(currentPlayer, rowSelected, colSelected);
// Here's to switch player
currentPlayer = (currentPlayer == Token.BLUE_TOKEN) ? Token.RED_TOKEN : Token.BLUE_TOKEN;
}
} else {
initGame();
}
// Drawing canvas are refresh
repaint();
}
});
// Setup the status bar (JLabel) to display status message
statusBar = new JLabel(" ");
statusBar.setFont(new Font(Font.DIALOG_INPUT, Font.BOLD, 15));
statusBar.setBorder(BorderFactory.createEmptyBorder(2, 5, 4, 5));
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
cp.add(canvas, BorderLayout.CENTER);
cp.add(statusBar, BorderLayout.NORTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setTitle("Phagocyte by esQmo");
setVisible(true);
board = new Token[ROWS][COLS];
initGame();
}
/** The game board contents and the status are initialised here*/
public void initGame() {
for (int row = 0; row < ROWS; ++row) {
for (int col = 0; col < COLS; ++col) {
board[row][col] = Token.EMPTY;
}
}
currentState = GameState.PLAYING;
currentPlayer = Token.RED_TOKEN;
}
/*this part need some improvements since hasWon and isDraw are not yet definied*/
public void updateGame(Token theToken, int rowSelected, int colSelected) {
if (hasWon(theToken, rowSelected, colSelected)) {
currentState = (theToken == Token.RED_TOKEN) ? GameState.RED_TOKEN_WON : GameState.BLUE_TOKEN_WON;
} else if (isDraw()) {
currentState = GameState.DRAW;
}
}
/** This is supposed to return true if it is a draw (no more empty cell for exemple) */
/** need to be improved **/
/* public boolean isDraw() {
for (int row = 0; row < ROWS; ++row) {
for (int col = 0; col < COLS; ++col) {
if (board[row][col] == Token.EMPTY) {
return false;
}
}
}
return true;
} */
/**Need to implement a Win scenario as well **/
public boolean hasWon(Token theToken, int rowSelected, int colSelected){
//
}
class DrawCanvas extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.WHITE);
//Grid lines
g.setColor(Color.LIGHT_GRAY);
for (int row = 1; row < ROWS; ++row) {
g.fillRoundRect(0, CELL_SIZE * row - GRID_WIDHT_HALF,
CANVAS_WIDTH-1, GRID_WIDTH, GRID_WIDTH, GRID_WIDTH);
}
for (int col = 1; col < COLS; ++col) {
g.fillRoundRect(CELL_SIZE * col - GRID_WIDHT_HALF, 0,
GRID_WIDTH, CANVAS_HEIGHT-1, GRID_WIDTH, GRID_WIDTH);
}
// This draw the Tokkens in the cells if they are not empty
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke(SYMBOL_STROKE_WIDTH, BasicStroke.CAP_ROUND,
BasicStroke.JOIN_ROUND));
for (int row = 0; row < ROWS; ++row) {
for (int col = 0; col < COLS; ++col) {
int x1 = col * CELL_SIZE + CELL_PADDING;
int y1 = row * CELL_SIZE + CELL_PADDING;
if (board[row][col] == Token.RED_TOKEN) {
int x2 = (col + 1) * CELL_SIZE - CELL_PADDING;
int y2 = (row + 1) * CELL_SIZE - CELL_PADDING;
g2d.setColor(Color.RED);
g2d.drawOval(x1, y1, SYMBOL_SIZE, SYMBOL_SIZE);
g2d.fillOval(x1, y1, SYMBOL_SIZE, SYMBOL_SIZE);
} else
if (board[row][col] == Token.BLUE_TOKEN) {
g2d.setColor(Color.BLUE);
g2d.drawOval(x1, y1, SYMBOL_SIZE, SYMBOL_SIZE);
g2d.fillOval(x2, y1, SYMBOL_SIZE, SYMBOL_SIZE);
}
}
}
// Print status-bar message
if (currentState == GameState.PLAYING) {
statusBar.setForeground(Color.BLACK);
if (currentPlayer == Token.RED_TOKEN) {
statusBar.setText("Red, it's your move");
statusBar.setForeground(Color.RED);
} else {
statusBar.setText("Blue, it's your move");
statusBar.setForeground(Color.BLUE);
statusBar.addMouseMotionListener(null);
}
} else if (currentState == GameState.DRAW) {
statusBar.setForeground(Color.RED);
statusBar.setText("It's a draw!");
} else if (currentState == GameState.RED_TOKEN_WON) {
statusBar.setForeground(Color.RED);
statusBar.setText("Red wow!");
} else if (currentState == GameState.BLUE_TOKEN_WON) {
statusBar.setForeground(Color.BLUE);
statusBar.setText("Blue Won! ");
}
}
}
public static void main(String[] args){
SwingUtilities.invokeLater(() -> {
Phagocyte phagocyte = new Phagocyte();
});
}
}
I'm unable to post image, due to my reputation :'(
I am well and truly stuck on this method. I need to create an attack method for a ComputerPlayer that chooses a random location and attacks the other player's board. Then, there is an attack method where I have to just attack the other player's board. However, when I run the program and place my guesses on my board (GUI), the dots just appear on the ComputerPlayer's board. I don't know why my methods are wrong though.
/**
* Attack the specified Location loc. Marks
* the attacked Location on the guess board
* with a positive number if the enemy Player
* controls a ship at the Location attacked;
* otherwise, if the enemy Player does not
* control a ship at the attacked Location,
* guess board is marked with a negative number.
*
* If the enemy Player controls a ship at the attacked
* Location, the ship must add the Location to its
* hits taken. Then, if the ship has been sunk, it
* is removed from the enemy Player's list of ships.
*
* Return true if the attack resulted in a ship sinking;
* false otherwise.
*
* #param enemy
* #param loc
* #return
*/
#Override
public boolean attack(Player enemy, Location loc)
{
int[][] array = getGuessBoard();
if(!enemy.hasShipAtLocation(loc))
array[loc.getRow()][loc.getCol()] = -1;
else
{
array[loc.getRow()][loc.getCol()] = 1;
enemy.getShip(loc).takeHit(loc);
}
if(enemy.getShip(loc).isSunk()) {
enemy.removeShip(enemy.getShip(loc));
return true;
}
return false;
}
#Override
public boolean attack(Player enemy, Location loc)
{
int range = (10 - 0) + 1;
int r = (int) Math.random() * range;
int c = (int) Math.random() * range;
int[][] array = getGuessBoard();
if(array[r][c] != -1)
{
if(!enemy.hasShipAtLocation(loc))
array[loc.getRow()][loc.getCol()] = -1;
else
{
array[loc.getRow()][loc.getRow()] = 1;
enemy.getShip(loc).takeHit(loc);
}
if(getShip(loc).isSunk())
{
enemy.removeShip(enemy.getShip(loc));
return true;
}
}
return false;
}
GUI for Game
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
public class BattleshipDriver extends Canvas implements MouseListener
{
public static final int WIDTH = 1024, HEIGHT = WIDTH / 12 * 9;
private Battleship battleship;
private int x, y, squareSize, len;
private Player p1, p2;
private BufferedImage logo, end;
public BattleshipDriver()
{
battleship = new Battleship();
battleship.addPlayer(new HumanPlayer("Mr. Hubbard"));
battleship.addPlayer(new ComputerPlayer("AlphaBattleship"));
x = 90;
y = 200;
squareSize = 36;
len = squareSize * 10 - 1;
p1 = battleship.getPlayer(0);
p2 = battleship.getPlayer(1);
// Get Battleship Logo
try {
logo = ImageIO.read(new File("src/Logo.png"));
} catch (IOException e) {
e.printStackTrace();
}
// Get End Screen
try {
end = ImageIO.read(new File("src/End.png"));
} catch (IOException e) {
e.printStackTrace();
}
addMouseListener(this);
new Window(WIDTH, HEIGHT, "Battleship", this);
try {
Thread.sleep(100);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
render();
}
private void render()
{
Graphics g = getGraphics();
// Background
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, WIDTH, HEIGHT);
if(!battleship.gameOver())
{
// Boards
renderGrid(g, x, y, squareSize);
renderGuesses(g, p1, x, y, squareSize);
renderGrid(g, 570, y, squareSize);
renderGuesses(g, p2, 570, y, squareSize);
// Names
g.setColor(Color.WHITE);
g.drawString(p1.getName(), x, y + 25 + len);
g.drawString(p2.getName(), 570, y + 25 + len);
}
else
{
// End Screen
g.drawImage(end, 0, 0, this);
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", 1, squareSize));
String winner = battleship.getWinner().getName();
g.drawString(winner, WIDTH / 2 - (winner.length() * squareSize / 4), HEIGHT / 4);
g.drawString("Wins!", WIDTH / 2 - ("Wins!".length() * squareSize / 4), HEIGHT / 4 + squareSize);
}
// Battleship Logo
g.drawImage(logo, WIDTH / 2 - 246, 10, this);
g.dispose();
}
private void renderGrid(Graphics g, int x, int y, int s)
{
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", 1, s / 2));
// Row Lines
for(int i = 0; i < 11; i++)
g.drawLine(x, y+i*s, x+len, y+i*s);
// Column Lines
for(int i = 0; i < 11; i++)
g.drawLine(x+i*s, y, x+i*s, y+len);
// Row Markers
for(int i = 0; i < 10; i++) //marks row coordinates on side
g.drawString(i + "", x-(int)(s*0.43), y+(int)(s*0.67)+s*i);
// Column Markers
for(int i = 0; i < 10; i++) //marks column coordinates on top
g.drawString(i + "", x+(int)(s*0.4)+s*i, y-(int)(s*0.2));
}
public void renderGuesses(Graphics g, Player player, int x, int y, int s)
{
int[][] guessBoard = player.getGuessBoard();
for(int r = 0; r < guessBoard.length; r++)
for(int c = 0; c < guessBoard[r].length; c++)
if(guessBoard[r][c] > 0) // hit
{
g.setColor(Color.RED);
g.fillOval(c*s+x+(int)(s*0.35), r*s+y+(int)(s*0.35), (int)(s*0.33), (int)(s*0.33));
}
else if(guessBoard[r][c] < 0) // miss
{
g.setColor(Color.WHITE);
g.fillOval(c*s+x+(int)(s*0.35), r*s+y+(int)(s*0.35), (int)(s*0.33), (int)(s*0.33));
}
}
#Override
public void mouseClicked(MouseEvent e)
{
int r = e.getY();
int c = e.getX();
int len = squareSize * 10 - 1;
if(r > y && r < y + len && c > x && c < x + len) // clicked on board
{
int row = (r - y) / squareSize;
int col = (c - x) / squareSize;
System.out.println(row + ", " + col);
Location loc = new Location(row, col);
if(p1.getGuessBoard()[row][col] == 0)
{
p1.attack(p2, loc);
p2.attack(p1, loc);
}
battleship.upkeep();
render();
}
System.out.println(r + ", " + c);
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
public static void main(String[] args)
{
new BattleshipDriver();
}
}
I am new to programming and this is my first time posting to this site. I am currently working on an assignment which will allow a user to input a number between 1 and 20, and then will create a brick wall based upon the number of brick layers the user entered into the JTextField. I was able to create one row, but I don't really understand nesting statements, and all of the examples I've looked at on the web just confuse me more, so I was wondering if someone could possibly help me to better understand nesting for-loops.
//Package List
import java.awt.*;
import java.applet.*;
import javax.swing.*;
import java.util.*;
import java.awt.event.*;
public class Wall extends JApplet implements KeyListener {
//Component declaration
JLabel directions;
JTextField input;
//Variable declaration
int startX = 50;
int startY = 650;
int width = 50;
int height = 20;
int spacing = 2;
//Method declaration
public void init()
{
getContentPane().setBackground(new Color (128, 128, 128));//Changes backround of JApplet to black
//Set JTextField and JLabel
setLayout (new FlowLayout( ));
directions = new JLabel("Enter in any number between 1 and 20 and then press Enter on your keyboard.");
input = new JTextField ( 10 );
add (directions );
add (input);
//Key listener
addKeyListener( this );
setFocusable( true );
}
//Method declaration
public void paint(Graphics g)
{
super.paint (g);
for (int col=1; col<= 8; col++)
{
// for (int row; row<=20; row++)
{ g.setColor (Color.RED);
g.fillRect (startX, startY, 50, 20);
startX = startX + spacing + width;
}
}
}
//Key event methods
public void keyReleased( KeyEvent ke ){}
public void keyTyped (KeyEvent ke ) {}
public void keyPressed ( KeyEvent ke )
{
int key = ke.getKeyCode ( );
if (key == KeyEvent.VK_ENTER)
{
}
}
You need to calculate the x/y position of the brick based on the current row/col. Now, you could simply initialise these values at the start of each loop and increment as required, or you could use a little maths...
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.JApplet;
import javax.swing.JLabel;
import javax.swing.JTextField;
public class AnotherBrickInTheWall extends JApplet {
//Component declaration
JLabel directions;
JTextField input;
//Variable declaration
int startX = 0;
int startY = 50;
int width = 50;
int height = 20;
int spacing = 2;
//Method declaration
public void init() {
getContentPane().setBackground(new Color(128, 128, 128));//Changes backround of JApplet to black
//Set JTextField and JLabel
setLayout(new FlowLayout());
directions = new JLabel("Enter in any number between 1 and 20 and then press Enter on your keyboard.");
input = new JTextField(10);
add(directions);
add(input);
}
//Method declaration
#Override
public void paint(Graphics g) {
super.paint(g);
for (int row = 0; row < 8; row++) {
int y = startY + (row * (height + spacing));
for (int col = 0; col < 8; col++) {
int x = startX + (col * (width + spacing));
System.out.println(x + "x" + y);
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
}
}
}
Now, you should never paint on a component which has components added to, this will cause the painting to appear over the top of the components and end up with all sorts of painting issues.
Instead, create a custom component, extending from something like JPanel and override it's paintComponent method instead and place your custom painting here.
You could then add your controls another JPanel and using a BorderLayout on your applet, add these two panels, the fields in the NORTH position and wall in the CENTER position
Updated
If you wanted to get "really" fancy, you could even adjust the x position based on the current row, for example...
int xOffset = 0;
for (int row = 0; row < 8; row++) {
int y = startY + (row * (height + spacing));
if (row % 2 == 0) {
xOffset = width / 2;
} else {
xOffset = 0;
}
for (int col = 0; col < 8; col++) {
int x = xOffset + (startX + (col * (width + spacing)));
System.out.println(x + "x" + y);
g.setColor(Color.RED);
g.fillRect(x, y, width, height);
}
}
Also, JTextField is has an ActionListener which is triggered when the field is actioned, typically by the user pressing Enter. This means that you shouldn't need the KeyListener.
See How to Use Text Fields for more details.
int x=num //1-20
int step=num/8;
int last_row=num%8;
for(int j=1;j<=step;j++){
int nos=8;
if(j == step && last_step ! = 0)
nos = last_step;
for (int col=1; col<= nos; col++)
{
g.setColor (Color.RED);
g.fillRect (startX, startY, 50, 20);
startX = startX + spacing + width;
startY = startY*j;
}
}
Try this.
I am having a bit of trouble making this grid be drawn 10 pixels from the top and 10 pixels from the left of the Frame.
I can make it do it by increasing this.getY() + 10 to a higher number, just wondering why if is remove the + 10 it getting drawn off screen.
Ignore the variable names and any formatting I just threw this together
package griddrawing;
import java.awt.*;
import javax.swing.*;
public class Grid extends JFrame
{
private int TILEWIDTH;
private int TILEHEIGHT;
private int COLS;
private int ROWS;
private int defaultX;
private int defaultY;
private int currentX;
private int currentY;
public Grid()
{
setSize(800,400);
TILEWIDTH = 30;
TILEHEIGHT = 30;
COLS = 10;
ROWS = 10;
defaultX = this.getX() + 10;
defaultY = this.getY() + 10;
currentX = 0;
currentY = 0;
}
#Override
public void paint(Graphics g)
{
super.paint(g);
currentX = defaultX;
currentY = defaultY;
g.setColor(Color.black);
for(int i = 0; i < COLS; i++)
{
for(int k = 0 ; k < ROWS; k++)
{
g.drawRect(currentX - (TILEWIDTH / 2), currentY - (TILEHEIGHT / 2), TILEWIDTH, TILEHEIGHT);
g.drawString("" + k, currentX, currentY);
currentY += TILEWIDTH;
System.out.println("COL: " + i + " ROW: " + k + " Current X: " + currentX + " Current Y: " + currentY);
}
currentY = defaultY;
currentX += TILEHEIGHT;
}
}
}
Don't set the size of the frame.
Don't paint directly to the frame either.
Instead of both:
Override the paintComponent(Graphics) method of a JComponent or JPanel.
Either call theComponent.setPreferredSize(Dimension) or override that same method.
Add the custom component to the frame and call pack().
That lot should mean you no longer need to account for any offset (which might change by platform or PLAF).
I'm working with java images for the first time and having a problem viewing them when the applet loads. If I resize the window they display fine. I feel like this is a common first-timer error. Has anyone else encountered this? Any idea what the fix could be? What I believe to be the pertinent parts of the code are listed below. Thanks for any and all help with this...
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
public class example extends JApplet implements Runnable
{
boolean updating;
Thread thread;
private int width, height;
Table aTable; //used to create and store values
private AudioClip[] sounds = new AudioClip[4]; //array to hold audio clips
private int counter = 0; //counter for audio clip array
private Image GameImage;
private Graphics GameGraphics;
public example() //set up applet gui
{
this.resize(new Dimension(600, 500));
//setup table
aTable = new Table(50, 50, 50, 50, 16, 16, getImage("images/FLY.gif", Color.white),
getImage("images/FlySwatter.gif", Color.white)); //Table must be square or flyswatter wont move straight
//add cordTxtFlds to bottom of screen
//this.add(cordTxtFlds, BorderLayout.SOUTH);
super.resize(800, 600);
repaint();
}
public void init()
{
width = getSize().width;
height = getSize().height;
GameImage = createImage(width, height);
GameGraphics = GameImage.getGraphics();
// Automatic in some systems, not in others
GameGraphics.setColor(Color.black);
repaint();
validate();
//show the greeting
ImageIcon icon = new ImageIcon("images/FLY.gif",
"a fly");
repaint();
validate();
}
/** Description of paint(Graphics g)
*
* Function draws table and sets the table color
* #param g graphics object used to draw table
* #return void
*/
public void paint(Graphics g)
{
GameGraphics.clearRect(0, 0, getWidth(), getHeight());
aTable.draw(GameGraphics);
g.drawImage(GameImage, 0, 0, this);
}
public void update(Graphics g)
{
paint(g);
validate();
}
public void start()
{
thread = new Thread(this);
thread.start();
}
public void stop()
{
updating = false;
}
public void run()
{
while(updating)
{
aTable.update();
}
}
//returns a transparent image.
//color is made transparent
private Image getImage(String imgPath, final Color color)
{
Image img = Toolkit.getDefaultToolkit().getImage(imgPath);
ImageFilter filter = new RGBImageFilter() {
// the color we are looking for... Alpha bits are set to opaque
public int markerRGB = color.getRGB() | 0xFFFFFF;
public final int filterRGB(int x, int y, int rgb) {
if ( ( rgb | 0xFF000000 ) == markerRGB ) {
// Mark the alpha bits as zero - transparent
return 0x00FFFFFF & rgb;
}
else {
// nothing to do
return rgb;
}
}
};
ImageProducer ip = new FilteredImageSource(img.getSource(), filter);
img = Toolkit.getDefaultToolkit().createImage(ip);
return img;
}
}
and the class which handles the drawing (in drawValues())
import java.awt.*;
import java.util.Random;
public class Table extends Panel
{
private char[][]values = new char[10][10]; //probably better to use array of integer values(0 or 1)
private Point[]coordLoc;// = new Point[100]; //stores the x & y coordinates of points on the grid
private boolean[]itemMarker; //stores the truth value of wether or not an item
// is located at the coresponding point in cordLoc array
private int [][]coords;// = new int [100][2];
Image itemImg; // stores the item image
private int Rows; // stores number of rows
private int Columns; // stores number of columns
private int BoxWidth ; // stores the width of a box
private int BoxHeight; // stores the height of a box
public Point Pos = new Point(); // creates a new point to draw from
private int tableHeight; // stores the height of the table
private int tableWidth; // stores the width of the table
private int numOfGridLocs;
/** Description of public Table( x, y, width, height, col, rows, X, O)
*
* Constructor function
* #param x contains an x-coordinate of the table
* #param y contains a y-coordinate of the table
* #param width contains the width of a box in the table
* #param height contains the height of a box in the table
* #param col contains the number of columns in the table
* #param rows contains the number of rows in the table
* #param itemImg contains the "target" image ie: ant, fly, ... unicorn
* #return none
*/
public Table(int x, int y, int width, int height, int col, int rows, Image itemImg, Image swatterImg)
{
/*set values*/
numOfGridLocs = (col - 1) * (rows - 1);
//initialize arrays
coordLoc = new Point[numOfGridLocs];
for(int i = 0; i < numOfGridLocs; i++)
coordLoc[i] = new Point();
Rows = rows;
Columns = col;
BoxWidth = width;
BoxHeight = height;
Pos.x = x;
Pos.y = y;
this.itemImg = itemImg;
tableHeight = Rows*BoxHeight;
tableWidth = Columns*BoxWidth;
itemMarker = new boolean[numOfGridLocs];
coords = new int [numOfGridLocs][2];
this.setValues();
mapGrid();
}
/** Description of draw(Graphics g)
*
* Function draws the lines used in the table
* #param g object used to draw the table
* #return none
*/
public void draw(Graphics g)
{
Graphics2D g2=(Graphics2D)g;
//draw flyswatter
drawValues(g2); //draw values
//draw vertical table lines
for (int i = 0 ; i <= Columns ; i++)
{
//make center line thicker
if(i == Rows/2)
g2.setStroke(new BasicStroke(2));
else
g2.setStroke(new BasicStroke(1));
g2.drawLine(i*BoxWidth + Pos.x, Pos.y, i*BoxWidth + Pos.x, tableHeight+Pos.y);
}
//draw horizontal table line
for(int i = 0 ; i <= Rows ; i++)
{
//make center line thicker
if(i == Rows/2)
g2.setStroke(new BasicStroke(2));
else
g2.setStroke(new BasicStroke(1));
g2.drawLine(Pos.x, i*BoxHeight + Pos.y, tableWidth+Pos.x, i*BoxHeight + Pos.y);
}
drawLables(g);
}
/** Description of drawLables(Graphics g)
*
* Function draws the Lables of the Table
* #param g object used to draw the table
* #return none
*/
private void drawLables(Graphics g)
{
String Lable;
Graphics2D g2 = (Graphics2D)g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Font font = new Font("Serif", Font.PLAIN, 10);
g2.setFont(font);
int xLabel = this.Columns/2 * -1;
int yLabel = this.Rows/2;
//draw Row lables
for (int i = 0 ; i <= Rows ; i++)
{
Lable = "" + yLabel;
g2.drawString(Lable, Pos.x - 25, Pos.y + BoxHeight*i);
yLabel--;
}
//draw Column lables
for (int i = 0 ; i <= Columns ; i++)
{
Lable = "" + xLabel;
g2.drawString(Lable, Pos.x + BoxWidth*i - 5, Pos.y - 20 );
xLabel++;
}
}
/** Description of randomChangeFunc()
*
* Function randomly determines which table value to change
* #param none
* #return void
*/
public int getX(int XCordinate)
{
int x = XCordinate+Columns/2;
if(x < 0) x *= -1; //x must be positive
x *= BoxWidth;
x += Pos.x;
return x-BoxWidth/2;
}
//returns Position of Y-cordinate
public int getY(int YCordinate)
{
int y = YCordinate -Rows/2;
if (y < 0) y *= -1; //y must be positive
y *= BoxHeight;
y += Pos.y;
return y-BoxHeight/2;
}
/** Description of getValue( col, row )
*
* Function draws the lines used in the table
* #param col contains a column coordinate
* #param row contains a row coordinate
* #return returns table coordinates
*/
public char getValue(int col, int row)
{
return values[row][col];
}
/** Description of isDrawable( x, y )
*
* Function returns true if (x,y) is a point in the table
* #param x contains a table column
* #param y contains a table row
* #return boolean if (x,y) is a point in the table
*/
public boolean isDrawable(int x, int y)
{
if((this.getRow(y)!=-1)||(this.getColumn(x)!=-1))
return true;
else
return false;
}
private void drawValues(Graphics g)
{
for(int i = 0; i < numOfGridLocs; i++)
if(itemMarker[i])
g.drawImage(itemImg,coordLoc[i].x+1, coordLoc[i].y+1, BoxWidth-1, BoxHeight-1, null);
g.setColor(Color.black); // set color of table to black
}
//sets the randomized boolean values in itemMarker array
private void setValues()
{
double probOfItem = .25;
for(int count = 0; count < numOfGridLocs; count++){
itemMarker[count] = randomBool(probOfItem);
if(itemMarker[count])
System.out.println("true");
else
System.out.println("false");
}
}
//returns random boolean value, p is prob of 'true'
private boolean randomBool(double p)
{
return (Math.random() < p);
}
public int getColumn(int x)
{
x += (BoxWidth/2); //aTable.getX/Y returns in the middle of squares not at upper left point
int offsetx=0;
for (int i = 0 ; i < Columns*2 ; i++)
{
offsetx = i*BoxWidth;
if((x>=Pos.x+offsetx)&& (x<Pos.x+offsetx+BoxWidth))
return i-Columns;
}
return -100;
}
public int getRow(int y)
{
int offsety=0;
y += (BoxHeight/2); //aTable.getX/Y returns in the middle of squares not at upper left point
for (int i = 0 ; i < Rows*2 ; i++) {
offsety = i * BoxHeight;
if((y >= (offsety+Pos.y))&& (y < (offsety+BoxHeight+Pos.y)))
{
return ((i)*-1)+Rows;
}
}
return -100;
}
public boolean isValidGuess(int x, int y)
{
if ((x > Columns/2) || (x < Columns/2*-1) || (y > Rows/2) || (y < Rows/2*-1))
return false;
return true;
}
/** Description of randomChangeFunc()
*
* Function randomly determines which table value to change
* #param none
* #return void
*/
public void randomChangeFunc()
{
//get random row and column
Random rand=new Random();
int randRow = rand.nextInt(Rows); // gets and holds a random column
int randCol = rand.nextInt(Columns); // gets and holds a random column
System.out.println("randRow = " + randRow + " randCol = " + randCol);
if(values[randRow][randCol] == 'X')
values[randRow][randCol] = 'O';
else if(values[randRow][randCol] == 'O')
values[randRow][randCol] = 'X';
else
System.out.println("ERROR SWAPPING SQUARE VALUE"); // error message
}
private void mapGrid() //set values for coordLoc array
{
//set counter variables
int count = 0;
int index = 0;
//loop through all points, assigning them to the coordLoc array
for (int r=0; r < Rows-1; r++)
for (int c=0; c < Columns-1; c++) {
//the width/height / 2 places the points on grid line intersections, not the boxes they create
coordLoc[count].x = Pos.x + (BoxWidth) * c + (BoxWidth/2); // record x-point
coordLoc[count].y = Pos.y + (BoxHeight) * r + (BoxHeight/2); // record y-point
System.out.println(coordLoc[count].getX() + ", " + coordLoc[count].getY());
count++;
} //end inner for
//set positive x coord values for coords array
int y_axisBeginingIndex = (Rows - 2)/2;
for(int greaterIndex = 0; greaterIndex < ((Rows) / 2); greaterIndex++){
for(int minorIndex = 0; minorIndex < (Rows - 1); minorIndex++){
index = y_axisBeginingIndex + greaterIndex + ((Rows - 1) * minorIndex);
coords[index][0] = greaterIndex;
}
}
//set negative x coord values for coords array
for(int greaterIndex = -1; greaterIndex > (0-((Rows) / 2)); greaterIndex--){
for(int minorIndex = 0; minorIndex < (Rows - 1); minorIndex++){
index = y_axisBeginingIndex + greaterIndex + ((Rows - 1) * minorIndex);
coords[index][0] = greaterIndex;
}
}
//set positive y values for coords array
int x_axisBeginingIndex = (Rows - 1) * ((Rows / 2) - 1);
for(int greaterIndex = 0; greaterIndex < ((Rows) / 2); greaterIndex++){
for(int minorIndex = 0; minorIndex < (Rows - 1); minorIndex++){
index = x_axisBeginingIndex + minorIndex;
coords[index][1] = greaterIndex;
}
x_axisBeginingIndex -= (Rows - 1);
}
//set negative y values for coords array
x_axisBeginingIndex = (Rows - 1) * ((Rows / 2) - 1) + (Rows - 1);
for(int greaterIndex = -1; greaterIndex > (0-((Rows) / 2)); greaterIndex--){
for(int minorIndex = 0; minorIndex < (Rows - 1); minorIndex++){
index = x_axisBeginingIndex + minorIndex;
coords[index][1] = greaterIndex;
}
x_axisBeginingIndex += (Rows - 1);
}
//print out the x and y coords
for(int i = 0; i < numOfGridLocs; i++){
System.out.println("[" + i + "] -> x = " + coords[i][0] + " y = " + coords[i][1]);
}
}
public boolean thereIsAnItemAt(int index){
return itemMarker[index];
}
public boolean bugsLeft(){
boolean thereAreBugsLeft = false;
for(int i = 0; i < numOfGridLocs; i++)
if(itemMarker[i])
thereAreBugsLeft = true;
return thereAreBugsLeft;
}
void update()
{
this.repaint();
}
}
Been stumped on this for weeks. Thanks again...
What I believe to be the pertinent
parts of the code are listed below.
By definition when you have a problem you don't know what part of the code is (or isn't) relevant. That is why you need to post a SSCCE that demonstrates the problem so we can see what you are doing.
The fact that is work "after" a resize means the problem is not with the painting. The problem could be that the images aren't loaded in which case you should be using:
drawImage(...., this);
The "this" instead of "null" notifies the panel to repaint the image when the image gets fully loaded.
Or maybe, you added the panel to the frame after the frame was visible and forgot to use
panel.revalidate().
By resizing the frame you force a revalidation.
The point is we are guessing. So save us time and post a SSCCE next time.
Sorry still too much code.
You need to read the article on Painting in AWT and Swing. Your code is a mixture of both.
Basically, as you where told in your last posting custom painting is done by overriding the paintComponent(...) method of JPanel. So you do the custom painting and then add the JPanel to the JApplet. I gave you a link to the Swing tutorial in your last posting and it also contains a section on how to write an Applet.
You should be extending JPanel, not Panel.
Also, you should NOT be overriding the paint() and upated() method of JApplet, this is old AWT code and should NOT be used with Swing.
Read the article and fix the problems first.
The answer is changing the draw() method in the class that extends JPanel to paintComponent() and switching the last parameter in the call to drawImage() to 'this' instead of 'null'. Worked instantly and perfectly!