I can't get paintComponent() on JButton to work properly - java

I'm having a problem with the paintComponent() method of my JButton. I want to program my own Minesweeper game and when I try to repaint my Tiles(which extend JButton) they don't seem to update. Here is my Tile class:
package mineSweeper;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class Tile extends JButton{
/**
*
*/
private static final long serialVersionUID = 5476927382697663397L;
public static final int UNPRESSED = 0;
public static final int PRESSED = 1;
public static final int FLAG = 2;
public static final int BOMB = 3;
public static final int XBOMB = 4;
public static final int HEIGHT = 16;
public static final int WIDTH = 16;
private int paintMode = UNPRESSED;
public Tile(int x, int y){
super();
setBounds(x*WIDTH, y*HEIGHT, WIDTH, HEIGHT);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setMargin(new Insets(0, 0, 0, 0));
setBorder(BorderFactory.createEmptyBorder());
addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
setEnabled(false);
setPaintMode(PRESSED);
repaint();
}
});
}
public void reset(){
setEnabled(true);
setPaintMode(UNPRESSED);
repaint();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
if (getPaintMode()==UNPRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.setColor(Color.WHITE);
g.drawLine(0, 0, WIDTH-1, 0);
g.drawLine(0, 1, WIDTH-2, 1);
g.drawLine(0, 0, 0, HEIGHT-1);
g.drawLine(1, 0, 1, HEIGHT-2);
g.setColor(Color.GRAY);
g.drawLine(WIDTH, HEIGHT, 1, HEIGHT);
g.drawLine(WIDTH, HEIGHT-1, 2, HEIGHT-1);
g.drawLine(WIDTH, HEIGHT, WIDTH, 1);
g.drawLine(WIDTH-1, HEIGHT, WIDTH-1, 2);
}
if (getPaintMode()==PRESSED)
{
setBackground(Color.LIGHT_GRAY);
g.drawLine(0, 0, WIDTH, 0);
g.drawLine(0, 0, 0, HEIGHT);
}
g.dispose();
}
public int getPaintMode() {
return paintMode;
}
public void setPaintMode(int mode) {
mode = paintMode;
}
}
and the class Board
package mineSweeper;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Board extends JFrame{
/**
*
*/
private static final long serialVersionUID = 2769769568511334271L;
public static Tile[][] tile;
public JPanel panel = new JPanel(null);
public JButton resetButton = new ResetButton("Click here to Reset");
String input;
private static int screenWidth = 400;
private static int screenHeight = 400;
private static final int MAXROWS = 60;
private static final int MAXCOLUMS = 60;
private static final int MINROWS = 2;
private static final int MINCOLUMS = 6;
private static final int RESETBUTTONSIZE = 40;
public Board(){
super("MineSweeper");
askForInputs();
resetButton.setBounds(0, screenHeight, screenWidth, RESETBUTTONSIZE);
tile = new Tile[getColums()][getRows()];
pack();
setSize(screenWidth + getInsets().left + getInsets().right, screenHeight + getInsets().top + getInsets().bottom + RESETBUTTONSIZE);
getContentPane().add(panel);
panel.add(resetButton);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y] = new Tile(x,y);
panel.add(tile[x][y]);
}
}
setVisible(true);
}
private void askForInputs() {
try{
input = JOptionPane.showInputDialog(null, "Enter number of rows ( Maximum " + MAXROWS + " / Minimum " + MINROWS +")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINROWS)){
if (Integer.parseInt(input) > MAXROWS)
screenHeight = MAXROWS * Tile.HEIGHT;
}
else input = String.valueOf(MAXROWS/4);
screenHeight = Integer.parseInt(input) * Tile.HEIGHT;
try{
input = JOptionPane.showInputDialog(null, "Enter number of colums ( Maximum " + MAXCOLUMS + " / Minimum " + MINCOLUMS + ")" );
Integer.parseInt(input);
}
catch(Exception ex){input = "";}
if (!(input == null) && !(input.isEmpty()) && !(Integer.parseInt(input) < MINCOLUMS))
{
if (Integer.parseInt(input) > MAXCOLUMS)
screenWidth = MAXCOLUMS * Tile.WIDTH;
}
else input = String.valueOf(MAXCOLUMS/4);
screenWidth = Integer.parseInt(input) * Tile.WIDTH;
}
public static void reset(){
for (int x = 0; x < getColums(); x++)
{
for (int y = 0; y < getRows(); y++)
{
tile[x][y].reset();
}
}
}
public static int getScreenWidth() {
return screenWidth;
}
public static void setScreenWidth(int screenWidth) {
Board.screenWidth = screenWidth;
}
public static int getScreenHeight() {
return screenHeight;
}
public static void setScreenHeight(int screenHeight) {
Board.screenHeight = screenHeight;
}
public static int getColums(){
return getScreenWidth() / Tile.WIDTH;
}
public static int getRows(){
return getScreenHeight() / Tile.HEIGHT;
}
public static void main (String args[]){
new Board();
}
}
Don't mind the unused imports.
So my problem is: when I click a Tile I see I clicked it and I can't click it again but it looks the same like before.
What am I doing wrong please help.

There's a number of things pop out at me, but you're main problem is this...
public class Tile extends JButton {
//...
public void setPaintMode(int mode) {
mode = paintMode;
}
}
You never actually assign the current mode to the paintMode variable, the assignment is backwards.
I'd recommend using JFrame#setExtendedState to set the frame MAXIMIZED_BOTH state over the setSize hack you're currently using, it'll at least reduce the amount of code.
I'd also recommend using a GridLayout or GridBagLayout of a null layout any day.
Have you considered using a JToggleButton, it's basically what you're doing now?

Related

Why is my JFrame blank in my breakout game?

So I'm new at java and need some help with my breakout game. My JFrame is just blank and i don't know how to fix it?
So I have a ball class, paddle class, canvas class and a brick class as well as a main class. In my canvas class I set all functions the ball, paddle and bricks has etc. In brick class I draw the bricks. And in my main I do the JFrame but it's blank
Main class :
public class Main {
public static void main(String[] args){
JFrame frame = new JFrame();
Canvas c = new Canvas();
frame.add(c);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
I expect the JFrame to show the game instead of just blank window
package breakout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.KeyEvent;
import breakout.Bricks.Type;
public class Canvas extends JPanel implements ActionListener, MouseMotionListener, MouseListener, KeyListener {
/**
*
*/
private static final long serialVersionUID = 1L;
private static final int HEIGHT = 600;
public static final int WIDTH = 720;
private int horizontalCount;
private BufferedImage image;
private Graphics2D bufferedGraphics;
private Timer time;
private static final Font endFont = new Font(Font.SANS_SERIF, Font.BOLD, 20);
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private Paddle player;
private Ball ball;
ArrayList<ArrayList<Bricks>> bricks;
public Canvas() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
bufferedGraphics = image.createGraphics();
time = new Timer (15, this);
player = new Paddle((WIDTH/2)-(Paddle.PADDLE_WIDTH/2));
ball = new Ball (((player.getX() + (Paddle.PADDLE_WIDTH / 2 )) - (Ball.DIAMETER / 2)), (Paddle.Y_POS - (Ball.DIAMETER + 10 )), -5, -5);
bricks = new ArrayList<ArrayList<Bricks>>();
horizontalCount = WIDTH / Bricks.BRICK_WIDTH;
for(int i = 0; i < 8; ++i) {
ArrayList<Bricks> temp = new ArrayList<Bricks>();
#SuppressWarnings("unused")
Type rowColor = null;
switch(i) {
case 0 :
case 2:
rowColor = Type.LOW;
break;
case 1 :
case 3 :
case 5 :
rowColor = Type.MEDIUM;
break;
case 4 :
case 6 :
rowColor = Type.HIGH;
break;
case 7 :
default :
rowColor = Type.ULTRA;
break;
}
for(int j = 0; j < horizontalCount; ++j) {
Bricks tempBrick = new Bricks();
temp.add(tempBrick);
}
bricks.add(temp);
addMouseMotionListener(this);
addMouseListener(this);
addKeyListener(this);
requestFocus();
}
}
public void actionPerformed(ActionEvent e) {
checkCollisions();
ball.Move();
for(int i = 0; i < bricks.size(); ++i) {
ArrayList<Bricks> al = bricks.get(i);
for(int j = 0; j < al.size(); ++j) {
Bricks b = al.get(j);
if(b.dead()) {
al.remove(b);
}
}
}
repaint();
}
private void checkCollisions() {
if(player.hitPaddle(ball)) {
ball.setDY(ball.getDY() * -1);
return;
}
if(ball.getX() >= (WIDTH - Ball.DIAMETER) || ball.getX() <= 0) {
ball.setDX(ball.getDX() * -1);
}
if(ball.getY() > (Paddle.Y_POS + Paddle.PADDLE_HEIGHT + 10)) {
resetBall();
}
if(ball.getY() <= 0) {
ball.setDY(ball.getDY() * -1);
}
int brickRowActive = 0;
for(ArrayList<Bricks> alb : bricks) {
if(alb.size() == horizontalCount) {
++brickRowActive;
}
}
for(int i = (brickRowActive==0) ? 0 : (brickRowActive - 1); i < bricks.size(); ++i) {
for(Bricks b : bricks.get(i)) {
if(b.hitBy(ball)) {
player.setScore(player.getScore() + b.getBrickType().getPoints());
b.decrementType();
}
}
}
}
private void resetBall() {
if(gameOver()) {
time.stop();
return;
}
ball.setX(WIDTH/2);
ball.setDY((HEIGHT/2) + 80);
player.setLives(player.getLives() -1);
player.setScore(player.getScore() <= 1);
}
private boolean gameOver() {
if(player.getLives() <= 1) {
return true;
}
return false;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
bufferedGraphics.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(bufferedGraphics);
player.drawBall(bufferedGraphics);
for(ArrayList<Bricks> row : bricks) {
for(Bricks b : row) {
b.drawBrick(bufferedGraphics);
}
}
bufferedGraphics.setFont(scoreFont);
bufferedGraphics.drawString("Score: " + player.getScore(), 10, 25);
if(gameOver() && ball.getY() >= HEIGHT) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("Game Over Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT/2));
}
if(empty()) {
bufferedGraphics.setColor(Color.black);
bufferedGraphics.setFont(endFont);
bufferedGraphics.drawString("You won. Score: " + player.getScore(), (WIDTH /2) -85, (HEIGHT /2));
time.stop();
}
g.drawImage(image, 0, 0, this);
Toolkit.getDefaultToolkit().sync();
}
private boolean empty() {
for(ArrayList<Bricks> al : bricks) {
if(al.size() != 0) {
return false;
}
}
return true;
}
#Override
public void mouseMoved(MouseEvent e) {
player.setX(e.getX() - (Paddle.PADDLE_WIDTH / 2));
}
#Override
public void mouseClicked(MouseEvent e) {
if(time.isRunning()) {
return;
}
time.start();
}
#Override
public void mouseDragged(MouseEvent e) { }
#Override
public void mouseEntered(MouseEvent arg0) {}
#Override
public void mouseExited(MouseEvent arg0) {}
#Override
public void mousePressed(MouseEvent arg0) {}
#Override
public void mouseReleased(MouseEvent arg0) {}
#Override
public void keyPressed(KeyEvent arg0) {}
#Override
public void keyReleased(KeyEvent arg0) {}
#Override
public void keyTyped(KeyEvent arg0) {}
}
Preparing an MCVE, as required in SO, not only it makes helping much easier.
In many case, while preparing one, you are likely to find the problem, so it is a good debugging tool.
To answer "why is my JFrame blank ?" you could create the minimal code example like the following (copy-paste the entire code into GameBoard.java and run):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameBoard extends JPanel {
static final int HEIGHT = 600, WIDTH = 720, BRICK_ROWS = 8;
private final int horizontalCount;
private static final Font scoreFont = new Font(Font.SANS_SERIF, Font.BOLD, 15);
private final Paddle player;
private final Ball ball;
ArrayList<ArrayList<Brick>> bricks;
public GameBoard() {
super();
setPreferredSize( new Dimension(WIDTH, HEIGHT));
player = new Paddle(WIDTH/2-Paddle.PADDLE_WIDTH/2);
ball = new Ball (player.getX() + Paddle.PADDLE_WIDTH / 2 - Ball.DIAMETER / 2,
Paddle.Y_POS - (Ball.DIAMETER + 10 ));
bricks = new ArrayList<>();
horizontalCount = WIDTH / Brick.BRICK_WIDTH;
for(int i = 0; i < BRICK_ROWS; ++i) {
ArrayList<Brick> temp = new ArrayList<>();
for(int j = 0; j < horizontalCount; ++j) {
Brick tempBrick = new Brick(j*Brick.BRICK_WIDTH , Brick.BRICK_YPOS + i*Brick.BRICK_HEIGHT);
temp.add(tempBrick);
}
bricks.add(temp);
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2D = (Graphics2D)g;
g2D.clearRect(0, 0, WIDTH, HEIGHT);
player.drawPaddle(g2D);
ball.drawBall(g2D);
for(ArrayList<Brick> row : bricks) {
for(Brick b : row) {
b.drawBrick(g2D);
}
}
g2D.setFont(scoreFont);
g2D.drawString("Score: " + player.getScore(), 10, 25);
}
}
class Paddle{
public final static int PADDLE_WIDTH = 100, PADDLE_HEIGHT= 30, Y_POS = GameBoard.HEIGHT - 2* PADDLE_HEIGHT;
private int xPos, score;
Paddle(int xPos) {
this.xPos = xPos;
}
void setX(int xPos) {this.xPos = xPos;}
int getX() {return xPos;}
String getScore() {
return String.valueOf(score);
}
void drawPaddle(Graphics2D g2D) {
g2D.setColor(Color.GREEN);
g2D.fillRect(xPos, Y_POS, PADDLE_WIDTH, PADDLE_HEIGHT);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(400,250);
frame.add(new GameBoard());
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
class Brick{
final static int BRICK_WIDTH = 80, BRICK_HEIGHT = 15, BRICK_YPOS = 50;
int xPos, yPos;
Brick(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBrick(Graphics2D g2D) {
g2D.setColor(Color.RED);
g2D.fillRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
g2D.setColor(Color.BLACK);
g2D.drawRect(xPos, yPos, BRICK_WIDTH, BRICK_HEIGHT);
}
}
class Ball{
final static int DIAMETER = 40;
int xPos, yPos;
Ball(int xPos, int yPos) {
this.xPos = xPos;
this.yPos = yPos;
}
void drawBall(Graphics2D g2D) {
g2D.setColor(Color.BLUE);
g2D.fillOval(xPos, yPos, DIAMETER, DIAMETER);
}
}
This produces the following result, which I believe can serve as the basis of what you wanted to achieve:
Now start adding the missing functionality and see what breaks it.

I am creating a 2d game, i am trying to import some fonts but i keep getting the error

package aaron.game;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.*;
import javax.swing.JFrame;
import aaron.game.gfx.Colours;
import aaron.game.gfx.Font;
import aaron.game.gfx.Screen;
import aaron.game.gfx.SpriteSheet;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static final int WIDTH = 160;
public static final int HEIGHT = WIDTH / 12 * 9;
public static final int SCALE = 3;
public static final String NAME = "Game";
private JFrame frame;
public boolean running = false;
public int tickCount = 0;
private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
private int[] colours = new int[6*6*6];
private Screen screen;
public InputHandler input;
public Game(){
setMinimumSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));
setMaximumSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));
setPreferredSize(new Dimension(WIDTH*SCALE, HEIGHT*SCALE));
frame = new JFrame(NAME);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(this, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public void init(){
int index = 0;
for(int r = 0;r<6;r++){
for(int g = 0;g<6;g++){
for(int b = 0;b<6;b++){
int rr= (r*255/5);
int gg= (g*255/5);
int bb= (b*255/5);
colours[index++] = rr<<16| gg<<8 | bb;
}
}
}
screen = new Screen(WIDTH, HEIGHT, new SpriteSheet("/sprite_sheet.png"));
input = new InputHandler(this);
}
public synchronized void start() {
running = true;
new Thread(this).start();
}
public synchronized void stop() {
running = false;
}
public void run() {
long lastTime = System.nanoTime();
double nsPerTick = 1000000000D/60D;
int frames = 0;
int ticks = 0;
long lastTimer = System.currentTimeMillis();
double delta = 0;
init();
while (running){
long now = System.nanoTime();
delta += (now - lastTime) / nsPerTick;
lastTime = now;
boolean shouldRender = true;
while(delta >= 1){
ticks++;
tick();
delta -= 1;
shouldRender = true;}
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (shouldRender){
frames++;
render();
}
if(System.currentTimeMillis() - lastTimer >= 1000){
lastTimer += 1000;
System.out.println(ticks + " ticks, " + frames + " frames");
frames = 0;
ticks = 0;
}
}
}
public void tick(){
tickCount++;
if(input.up.isPressed()){screen.yOffset--;}
if(input.down.isPressed()){screen.yOffset++;}
if(input.left.isPressed()){screen.xOffset--;}
if(input.right.isPressed()){screen.xOffset++;}
for (int i = 0; i < pixels.length; i++){
pixels[i] = i + tickCount;
}
}
public void render(){
BufferStrategy bs = getBufferStrategy();
if (bs == null){
createBufferStrategy(3);
return;
}
for(int y=0;y<32;y++){
for(int x=0;x<32;x++){
boolean flipX = x%2==1;
boolean flipY = y%2==1;
screen.render(x<<3, y<<3, 0, Colours.get(555,505,055,550), flipX, flipY);
}
}
// Font.render("Hello Wolrd! 0157", screen, 0, 0, Colours.get(000, -1, -1, 555));
for(int y=0;y<screen.height;y++){
for(int x=0;x<screen.width;x++){
int colourCode=screen.pixels[x+y*screen.width];
if(colourCode<255)pixels[x+y*WIDTH]=colours[colourCode];
}
}
Graphics g = bs.getDrawGraphics();
//g.setColor(Color.BLACK);
//g.fillRect(0, 0, getWidth(), getHeight());
g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public static void main(String[] args){
new Game().start();
}
}
^This is my main class [ // Font.render("Hello Wolrd! 0157", screen, 0, 0, Colours.get(000, -1, -1, 555));] < this is where i am getting the error...
package aaron.game.gfx;
public class Font {
private static String chars = "" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ " + "0123456789.,:;'\"!?$%()-=+/ ";
public static void render(String msg, Screen screen, int x, int y, int colour, int scale) {
msg = msg.toUpperCase();
for (int i = 0; i < msg.length(); i++) {
int charIndex = chars.indexOf(msg.charAt(i));
if (charIndex >= 0) screen.render(x + (i * 8), y, charIndex + 30 * 32, colour, false, false);
}
}
}
This is the class for reading my fonts
package aaron.game.gfx;
public class Screen {
public static final int MAP_WIDTH = 64;
public static final int MAP_WIDTH_MASK = MAP_WIDTH - 1;
public int[]pixels;
public int xOffset = 0;
public int yOffset = 0;
public int width;
public int height;
public SpriteSheet sheet;
public Screen(int width, int height, SpriteSheet sheet){
this.width = width;
this.height = height;
this.sheet = sheet;
pixels=new int[width * height];
}
public void render(int xPos, int yPos, int tile, int colour){
render(xPos, yPos, tile, colour, false, false);
}
public void render(int xPos, int yPos, int tile, int colour, boolean mirrorX, boolean mirrorY){
xPos -= xOffset;
yPos -= yOffset;
int xTile = tile %32;
int yTile = tile /32;
int tileOffset=(xTile<<3)+(yTile<<3)*sheet.width;
for(int y=0;y<8;y++){
if(y+yPos<0 || y+yPos>=height)continue;
int ySheet = y;
if(mirrorY) ySheet = 7 - y;
for(int x=0;x<8;x++){
if(x+xPos<0 || x+xPos>=width)continue;
int xSheet = x;
if(mirrorX) xSheet = 7 - x;
int col=(colour>>(sheet.pixels[xSheet+ySheet*sheet.width+tileOffset]*8))&255;
if(col<255) pixels[(x+xPos)+(y+yPos)*width]=col;
}
}
}
}
This is my display class, anyway this error is killing me and i hae no idea how to fix it whatsoever, I have looked all over the place bot a single place, the error i am getting is
The method render(String, Screen, int, int, int, int) in the type Font is not applicable for the arguments (String, Screen, int, int, int)
Try cleaning and rebuilding the project. It seems like an older version of the program is being run...

JLabel won't display image - NullPointerException

this is my first Java GUI program, and really only my second java program, so take it easy on me :) My program is a result of a lot of googling and reading java docs. My problem is that I have a sprite sheet of 52 cards, and am attempting to save these cards individually to a Buffered Image array using subImage, and just for testing purposes, display all 52 in a window. The File is in the correct directory I made sure of that. I believe that my problem lies with my use of Jlabels, or simply a foolish mistake. Anyways, here is my class that does the sprite sheet splitting
package gui;
import java.awt.GridLayout;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class crdimgs extends JPanel {/**
*
*/
static final long serialVersionUID = 1L;
public final int width = 10;
public final int height = 20;
public int rows = 13;
public int cols = 5;
public BufferedImage image;
File cardimg = new File("Cards.jpg");
BufferedImage cards[];
public void loadsplit(File loadimage){
try{
image = ImageIO.read(loadimage);
} catch(Exception error){
System.out.print("error");
}
cards = new BufferedImage[cols*rows];
}
public crdimgs() {
loadsplit(cardimg);
setLayout(new GridLayout(rows, cols, 1, 1));
int x = 0;
int y = 0;
int subimg = 0;
for( int i = 0; i < rows; i++)
{
JPanel panel = new JPanel();
cards[subimg] = new BufferedImage(width, height, 5);
cards[subimg] = image.getSubimage(x, y, width, height);
panel.add(new JLabel(new ImageIcon(cards[subimg])));
add(panel);
x+=width;
subimg++;
}
y+=height;
x=0;
}
}
}
And my Main class
package gui;
import javax.swing.JFrame;
import java.awt.Color;
public class cards extends JFrame {
private static final long serialVersionUID = 1L;
public cards(){
setTitle("Poker");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(1000, 700);
setLocationRelativeTo(null);
this.getContentPane().setBackground(Color.GREEN);
setVisible(true);
setResizable(false);
add(new crdimgs());
}
public static void main(String[] args){
new cards();
}
}
Errors I receive at the moment are:
errorException in thread "main" java.lang.NullPointerException
at gui.crdimgs.<init>(crdimgs.java:53)
at gui.cards.<init>(cards.java:22)
at gui.cards.main(cards.java:28)
Likely your image is null, possibly because you're looking in the wrong place for it, but to find out, check out which line is 53.
Suggestions:
Start small and then build on. Don't try to do complex image manipulation until you first successfully read and show a single image.
Check where Java is looking for the image, because likely it isn't where you think it is. Put System.out.println(System.getProperty("user.dir")); in your code to find out.
Call setVisible(true) after adding all components to the JFrame.
Improve your exception display code by printing the stack trace: error.printStackTrace() (thanks Mad!).
For example:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
public class PlayingCardTest {
public static void main(String[] args) {
String pathToDeck = "http://www.jfitz.com/cards/classic-playing-cards.png";
try {
final List<ImageIcon> cardImgList = CreateCards.createCardIconList(pathToDeck);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame("Moving Cards");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new CardGameTable(cardImgList, frame));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
} catch (MalformedURLException e) {
e.printStackTrace();
System.exit(-1);
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
}
#SuppressWarnings("serial")
class CardGameTable extends JLayeredPane {
private static final int PREF_W = 600;
private static final int PREF_H = 400;
private static final Color BASE_COLOR = new Color(0, 80, 0);
private static final int CARD_COUNT = 20;
private static final int WIDTH_SHOWING = 20;
private JPanel basePane = new JPanel(null);
public CardGameTable(List<ImageIcon> cardImgList, final JFrame frame) {
basePane.setSize(getPreferredSize());
basePane.setBackground(BASE_COLOR);
add(basePane, JLayeredPane.DEFAULT_LAYER);
final MyMouseAdapter myMouseAdapter = new MyMouseAdapter(this, basePane);
addMouseListener(myMouseAdapter);
addMouseMotionListener(myMouseAdapter);
for (int i = 0; i < CARD_COUNT; i++) {
JLabel card = new JLabel(cardImgList.remove(0));
card.setSize(card.getPreferredSize());
int x = (PREF_W / 2) + WIDTH_SHOWING * (CARD_COUNT - 2 * i) / 2 -
card.getPreferredSize().width / 2;
int y = PREF_H - card.getPreferredSize().height - WIDTH_SHOWING * 2;
card.setLocation(x, y);
basePane.add(card);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
}
class MyMouseAdapter extends MouseAdapter {
private JLabel selectedCard = null;
private JLayeredPane cardGameTable = null;
private JPanel basePane = null;
private int deltaX = 0;
private int deltaY = 0;
public MyMouseAdapter(JLayeredPane gameTable, JPanel basePane) {
this.cardGameTable = gameTable;
this.basePane = basePane;
}
#Override
public void mousePressed(MouseEvent mEvt) {
Component comp = basePane.getComponentAt(mEvt.getPoint());
if (comp != null && comp instanceof JLabel) {
selectedCard = (JLabel) comp;
basePane.remove(selectedCard);
basePane.revalidate();
basePane.repaint();
cardGameTable.add(selectedCard, JLayeredPane.DRAG_LAYER);
cardGameTable.revalidate();
cardGameTable.repaint();
deltaX = mEvt.getX() - selectedCard.getX();
deltaY = mEvt.getY() - selectedCard.getY();
}
}
#Override
public void mouseReleased(MouseEvent mEvt) {
if (selectedCard != null) {
cardGameTable.remove(selectedCard);
cardGameTable.revalidate();
cardGameTable.repaint();
basePane.add(selectedCard, 0);
basePane.revalidate();
basePane.repaint();
selectedCard = null;
}
}
#Override
public void mouseDragged(MouseEvent mEvt) {
if (selectedCard != null) {
int x = mEvt.getX() - deltaX;
int y = mEvt.getY() - deltaY;
selectedCard.setLocation(x, y);
cardGameTable.revalidate();
cardGameTable.repaint();
}
}
}
class CreateCards {
private static final int SUIT_COUNT = 4;
private static final int RANK_COUNT = 13;
public static List<ImageIcon> createCardIconList(String pathToDeck)
throws MalformedURLException, IOException {
BufferedImage fullDeckImg = ImageIO.read(new URL(pathToDeck));
int width = fullDeckImg.getWidth();
int height = fullDeckImg.getHeight();
List<ImageIcon> iconList = new ArrayList<ImageIcon>();
for (int suit = 0; suit < SUIT_COUNT; suit++) {
for (int rank = 0; rank < RANK_COUNT; rank++) {
int x = (rank * width) / RANK_COUNT;
int y = (suit * height) / SUIT_COUNT;
int w = width / RANK_COUNT;
int h = height / SUIT_COUNT;
BufferedImage cardImg = fullDeckImg.getSubimage(x, y, w, h);
iconList.add(new ImageIcon(cardImg));
}
}
Collections.shuffle(iconList);
return iconList;
}
}
Which shows:

Undesirable repaint of a JPanel when dynamically updated

I have a window that dynamically updates the buffered image set on a JPanel using javax.swing.Timer
Everything works as expected but every time I invoke the dynamic update there seems to be another buffered image displayed below the currently updating one.
The image of the window before and after clicking the train button (which triggers the dynamic update) is given below.
Since the image below the dynamically updating image looks like the initial screen. I rechecked the following
Whether I'm adding two dynamic lattice objects to the same panel
Multiple calls of repaint()
Unwanted initialization of the dynamic lattice
I could not find any of these in my code. I cannot post the code since it is huge and whenever I'm creating a minimal set to reproduce the same behavior it is not there. So I'm sure I'm missing something or doing something on my project code which triggers this behavior. Any suggestions on how to debug this or why it is doing something like this?
Thank you
EDIT
SSCCE is give below. If executing, click the load button followed by the train button to get the error.
(MapScreen.java - Main Class)
package test;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import test.DisplayLattice;
import test.SelfOrganizingMap;
public class MapScreen extends JFrame {
private double NUM_ITERATIONS = 0.0;
private double ETA = 0.0;
private double SPREAD_FACTOR = 0.0;
private double RADIUS = 0.0;
private int WIDTH = 0;
private int HEIGHT = 0;
private SelfOrganizingMap SOM = null;
private Timer REFRESH_TIMER = null;
private JPanel pnlMap;
private JButton btnLoadParameters;
private JButton btnTrain;
private DisplayLattice displayScreen;
public MapScreen(double iterations, double learningRate, double spreadFactor, double radius, int option, int width, int height, int mapOption) {
NUM_ITERATIONS = iterations;
ETA = learningRate;
SPREAD_FACTOR = spreadFactor;
RADIUS = radius;
WIDTH = width;
HEIGHT = height;
setType(Type.UTILITY);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setTitle("Map");
setSize(650, 800);
setLocation(150,150);
getContentPane().setLayout(null);
displayScreen = new DisplayLattice();
pnlMap = displayScreen;
pnlMap.setBounds(6, 130, 600, 600);
getContentPane().add(pnlMap);
btnLoadParameters = new JButton("Load Parameters");
btnLoadParameters.setFont(new Font("Tahoma", Font.PLAIN, 11));
btnLoadParameters.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0)
{
SOM = new SelfOrganizingMap(10000,0,0,13,displayScreen);
}
});
btnLoadParameters.setBounds(192, 46, 126, 23);
getContentPane().add(btnLoadParameters);
btnTrain = new JButton("Train");
btnTrain.setFont(new Font("Tahoma", Font.PLAIN, 11));
btnTrain.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
initialObjectSetUp();
}
});
btnTrain.setBounds(192, 72, 62, 23);
getContentPane().add(btnTrain);
}
private void initialObjectSetUp()
{
SOM.initTrainSOM(null, 100, 0.25);
REFRESH_TIMER = new Timer(100, SOM);
REFRESH_TIMER.start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
MapScreen frame = new MapScreen(100,0.25,0.0,0.0,1,100,0,0);
frame.setVisible(true);
}
});
}
}
(SelfOrganizingMap.java)
package test;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class SelfOrganizingMap implements ActionListener {
private Node[][] SOM = null;
private double[][] NORM_MAP = null; //holds the L2 norm of each vector in the SOM[][].
#SuppressWarnings("unused")
private int GRID_OPTION = 0;
private int INPUT_DIMENSION = 0;
private int NUMER_OF_ITERATIONS = 0;
private int CURRENT_ITERATION=0;
private int SOM_HORIZONTAL_LENGTH = 0;
private int SOM_VERTICAL_LENGTH = 0;
private double INITIAL_LEARNING_RATE = 0.0;
private double LEARNING_RATE = 0.0;
private double MAX_RADIUS = 0.0; //radius at first epoch (t = 0)
private double RADIUS = 0.0;
private double TIME_STEP = 0.0; //lambda of X(t) = t0 * exp(-t/lambda)
private String INPUT_SAMPLES = null;
private DisplayLattice DISPLAY_SCREEN = null;
public SelfOrganizingMap(int numberOfNodes, int depth, int grid, int inputDimensison, DisplayLattice screen)
{
INPUT_DIMENSION = inputDimensison;
if(grid == 0)
{
int side = (int)Math.sqrt(numberOfNodes);
SOM = new Node[side][side];
NORM_MAP = new double[side][side];
GRID_OPTION = grid;
MAX_RADIUS = side/2;
DISPLAY_SCREEN = screen;
}
RADIUS = MAX_RADIUS;
}
public void initTrainSOM(String input, int iterations, double learningRate)
{
NUMER_OF_ITERATIONS = iterations;
INITIAL_LEARNING_RATE = learningRate;
LEARNING_RATE = INITIAL_LEARNING_RATE;
TIME_STEP = NUMER_OF_ITERATIONS/Math.log(MAX_RADIUS);
INPUT_SAMPLES = input;
}
private void singleCompleteRun()
{
DISPLAY_SCREEN.render();
System.out.println(CURRENT_ITERATION);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(CURRENT_ITERATION <= NUMER_OF_ITERATIONS)
{
singleCompleteRun();
CURRENT_ITERATION++;
}
}
}
(DisplayLattice.java)
package test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.*;
#SuppressWarnings("serial")
public class DisplayLattice extends JPanel {
private BufferedImage img = new BufferedImage(500, 500, 1);
public void paintComponent(Graphics g) {
if (img == null)
super.paintComponents(g);
else
g.drawImage(img, 0, 0, this);
}
public void render() {
float cellWidth = 100;
float cellHeight = 100;
int imgW = img.getWidth();
int imgH = img.getHeight();
float r, g, b;
Graphics2D g2 = img.createGraphics();
g2.setBackground(Color.black);
g2.clearRect(0,0,imgW,imgH);
for (int x=0; x<100; x++) {
for (int y=0; y<100; y++) {
r = (float)Math.random();
g = (float)Math.random();
b = (float)Math.random();
g2.setColor(new Color(r,g,b));
g2.fillRect((int)(x*cellWidth), (int)(y*cellHeight),
(int)cellWidth+1, (int)cellHeight+1);
}
}
g2.setColor(Color.black);
g2.dispose();
repaint();
}
public BufferedImage getImage() {
if (img == null)
img = (BufferedImage)createImage(500, 500);
return img;
}
public void setImage(BufferedImage bimg) {
img = bimg;
}
}
(Node.java - Structure class for the SOM)
package test;
public class Node {
private int DIMENSION = 0;
private int POSITION_X = 0;
private int POSITION_Y = 0;
private double ACTIVATION_VALUE = 0.0;
public Node(int Dimensions, int x, int y)
{
DIMENSION = Dimensions;
setWeightVector();
POSITION_X = x;
POSITION_Y = y;
}
public int getX() {
return POSITION_X;
}
public int getY() {
return POSITION_Y;
}
public double getACTIVATION_VALUE() {
return ACTIVATION_VALUE;
}
public void setPOSITION_X(int x) {
POSITION_X = x;
}
public void setPOSITION_Y(int y) {
POSITION_Y = y;
}
public void setACTIVATION_VALUE(double y) {
ACTIVATION_VALUE= y;
}
private void setWeightVector()
{
double temp[] = new double[DIMENSION];
for(int i = 0; i<temp.length ; i++)
{
temp[i] = Math.random();
}
}
}
The problem is your DiaplyLattice class.
You overrode paintComponent but you invoke super.paintComponents(g). Notice the extra s you have at the end of paintComponents! This of course is unwanted and should be super.paintComponent(g);
I would have you method as follow:
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (img != null) {
g.drawImage(img, 0, 0, this);
}
}
Now, just as a good advice/tip to give, don't use null layout and rather use LayoutManager's and possibly use several level of nesting. It's always easier.
Also, you missed an important thing in SSCCE: the SHORT part. Meaning that you should remove anything unnecessary and have a single file to copy/paste.

NullPointerException in my game, can't be fixed

I'm making an rpg with a custom pixel engine, and when I try to run it I just get a NullPointerException and I know why, but when I try to initialize that variable I get another one in a different location and I fix that and now it won't run at all and I still get a NullPointerException. This is the class that gets an error, and the console tells me that the error is on the line that says screen.render();
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.IOException;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import sprites.SpriteSheetLoader;
public class Game extends Canvas implements Runnable{
private static final long serialVersionUID = 1L;
public static final int HEIGHT = 120;
public static final int WIDTH = 120;
public static final int SCALE = 3;
public static final String NAME = "TypicalRPG";
public SpriteSheetLoader loader;
private BufferedImage img = new BufferedImage(WIDTH * SCALE, HEIGHT * SCALE, BufferedImage.TYPE_INT_RGB);
private int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
private boolean running = false;
private Screen screen = new Screen(WIDTH, HEIGHT, loader);
Random random = new Random();
public void start(){
running = true;
new Thread(this).start();
}
public static void main(String args[]){
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMaximumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
game.setMinimumSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
JFrame jf = new JFrame(NAME);
jf.add(game);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.pack();
jf.setVisible(true);
jf.setResizable(true);
game.start();
}
public void run(){
while(running){
tick();
render();
try{
Thread.sleep(5);
}
catch(InterruptedException e){ e.printStackTrace(); }
}
}
public void stop(){ running = false; }
public void tick(){
screen.render(0, 0, 0, 16, 16);
}
public void render(){
BufferStrategy bs = getBufferStrategy();
if(bs == null){
createBufferStrategy(3);
requestFocus();
return;
}
for(int i = 0; i < screen.pixels.length; i++){
pixels[i] = screen.pixels[i];
}
Graphics g = bs.getDrawGraphics();
g.drawImage(img, 0, 0, getWidth(), getHeight(), null);
g.dispose();
bs.show();
}
public void init(){
BufferedImage sheet = null;
try {
sheet = ImageIO.read(Game.class.getResourceAsStream("res/tiles.png"));
}
catch (IOException e) {
e.printStackTrace();
}
loader = new SpriteSheetLoader(sheet);
screen = new Screen(WIDTH, HEIGHT, loader);
}
}
and this is the class that has render():
import sprites.SpriteSheetLoader;
public class Screen{
public int[] pixels;
private SpriteSheetLoader loader;
private int w, h;
int xoff = 0, yoff = 0;
public Screen(int w, int h, SpriteSheetLoader loader){
this.loader = loader;
this.w = w;
this.h = h;
pixels = new int[w * h];
}
public void render(int xpos, int ypos, int tile, int width, int height){
loader.grabTile(tile, width, height);
xpos -= xoff;
ypos -= yoff;
for(int y = 0; y < height; y++){
if(ypos + y < 0 || ypos + y >= h) continue;
for(int x = 0; x < width; x++){
if(xpos + x < 0 || xpos + x >= w) continue;
int col = loader.pixels[x + (y * height)];
if(col != -65281) pixels[(x + xpos) + (y + ypos)] = col;
}
}
}
}
Seems like you never initiate the loader in your first class.
You define your variables like this:
public SpriteSheetLoader loader;
private Screen screen = new Screen(WIDTH, HEIGHT, loader);
Hence, you pass a null-object to your Screen. And from there you try to call a method on that null-object:
loader.grabTile(tile, width, height);
You have only declared loader, but never initiated it.
public SpriteSheetLoader loader;

Categories