why does my Jframe open an empty window? - java

I'm trying to make a game for school, like Puralax. This is my first year of Java.
Currently I'm testing through 'viewTest' and the 'DitMoetWerken.java' class to make my complete JFrame.
My guess is that the VakUI doesn't get painted but I don't know why. These should be the squares in my matrix.
This is where I call all my JFrames:
public class DitMoetWerken extends JFrame {
Spel spel;
public DitMoetWerken(Spel spel, int level) throws HeadlessException {
this.spel = spel;
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setSize(800,500);
setTitle("Puralax");
setVisible(true);
spel.beginLevel(level);
SpelFrame spelFrame = new SpelFrame(spel,new JButton("terugknop"),new JButton("resetknop"));
this.add(spelFrame,BorderLayout.CENTER);
This is where I make my roster for my game. It is a matrix where the length is 3x3 in this level:
public class SpelbordUI extends JPanel {
private final Spel spel;
private SpelRooster spelRooster;
private boolean vakChecker = false;
private Vak bewaardVak;
public SpelbordUI(Spel spel) {
this.spel = spel;
this.spelRooster = spel.getSpelRooster();
initAll();
}
private void initAll(){
this.removeAll();
this.setLayout(new GridLayout(spelRooster.getLengte(),spelRooster.getLengte(),20,20));
for (int i = 0; i < spelRooster.getLengte(); i++) {
for (int j = 0; j < spelRooster.getLengte(); j++) {
VakUI vak = new VakUI(spelRooster.getRooster()[i][j]);
this.add(vak);
}
}
}}
A 'vak' is meant to be a square in my language. Sorry for any possible confusion.
The class of this VakUI looks like this, where I think my problem is with the paintComponent. I think it should just fill up the vak's in VakUI because of the this.setBackground(kleur) or should I draw them in new squares?
public class VakUI extends JPanel {
private Color kleur;
private Vak vak;
public VakUI(Vak vak) {
this.vak = vak;
this.kleur = vak.getKleur();
}
public Vak getVak() {
return vak;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(kleur);
}}

In the class DitMoetWerken. setVisible(); is supposed to be placed underneath this.add(spelFrame,BorderLayout.CENTER);. this solved my empty window problem.

Related

Why do I get an error (Nullpointerexception) when trying to clear Canvas?

I have a project, in which I should create a robot that moves between randomly created squares, till it sticks between two squares, or it reaches the end of the Canvas. For that I have a Super class Figur that has two subclass (Kreis) Circle and (Rechteck) Square, I have a Class Spielfeld(Gamefield) that has methods to populate an arraylist of figure, commands that user gives, of what robot should do, ...and at the end of this methods it calls the method zeichnen(draw) from Class Leinwand(Canvas).
public abstract class Figur{
///..some fields, constructions, methhods..
abstract public void zeichnen(Graphics g);
}
public class Rechteck extends Figur{
///..some fields, constructions, methhods..
public void zeichnen(Graphics g){
g.setColor(getFarbe());
g.drawRect(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
g.fillRect(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
}
public class Kreis extends Figur{
public void zeichnen(Graphics g){
g.setColor(getFarbe());
g.drawOval(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
g.fillOval(getPosition().getX(),getPosition().getY(),getBreite(),getLaenge());
}
public class Spielfeld {
static ArrayList<Figur> myCharacters = new ArrayList<>();
//some methods that adds points(circles) and Squares to the arraylist MyCharacters
//some methods like movebetweensquares that calls method zeichnen in Leinwand
public class Leinwand{
public void zeichnen(ArrayList<Figur> figur){
loeschen();
zeichenflaeche.repaintFiguren(figur);
}
private void loeschen() {
Color original = graphic.getColor();
graphic.setColor(hintergrundfarbe);
Dimension size = zeichenflaeche.getSize();
graphic.fill(new Rectangle(0, 0, size.width, size.height));
graphic.setColor(original);
}
private class Zeichenflaeche extends JPanel {
private static final long serialVersionUID = 20060330L;
public void paintComponent(Graphics g){
super.paintComponent(g);
for(int j=0; j<Spielfeld.get_ myCharacters ().size();j++){
Figur s= Spielfeld.get_ myCharacters ().get(j);
s.zeichnen(g);
}
}
public void repaintFiguren(ArrayList<Figur> figuren{
for( Figur f: Spielfeld.get_ myCharacters ()){
for(int i=0; i<Spielfeld.get_ myCharacters ().size();i++){
if(f instanceof Rechteck){
repaint(figuren.get(i).getPosition().getX(),
figuren.get(i).getPosition().getY(),
figuren.get(i).getBreite(),figuren.get(i).getLaenge()); }
else if(f instanceof Kreis){
repaint(figuren.get(i).getPosition().getX(),
figuren.get(i).getPosition().getY(),
figuren.get(i).getBreite(),
figuren.get(i).getLaenge());}
}
}
}
}

Repaint a JPanel from within another JPanel

So, I am making a painting program and I have a main Paint class which detects mouse input and paints and a Tools class which is a toolbar on the left which holds a bunch of tools, like brush size change and shape change. So, I want to add a clear button to the Tools class which clears the whole screen. My problem is that the Paint class is holding the ArrayList of points which it paints and I can't repaint Paint from within Tools.
Paint class
//imports
public class Paint extends JPanel{
private ArrayList<Brush> points;
...
public Paint() {
...
}
public void paintComponent(Graphics page) {
...
//draws all points in the arraylist
for (Brush b : points) {
//paint points
}
}
}
Tools class
//imports
public class Tools extends JPanel
{
private JButton clear;
public Tools() {
clear = new JButton("Clear");
clear.addActionListener(new BrushInput());
}
public void paintComponent(Graphics page) {
...
}
private class BrushInput implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clear) {
//clear points arraylist and repaint
}
}
}
}
The issue I'm having is that repaint() is an instance method and so I can't access Paint's repaint from within Tools.
Just pass a reference to the Paint instance to Tools's constructor. Or, call repaint on the container (JFrame, etc.) that contains both of them, which should cause all its children to be repainted.
For example:
public class Paint extends JPanel {
private ArrayList<Brush> points;
// . . .
public void clear() {
points.clear();
repaint();
}
}
public class Tools extends JPanel {
private JButton clear;
private Paint paint;
public Tools(Paint paint) {
this.paint = paint;
// . . .
}
// . . .
private class BrushInput implements ActionListener {
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clear) {
paint.clear();
}
}
}
}
Code that creates these components:
Paint paint = new Paint();
Tools tools = new Tools(paint);

Making a Chess Board out of JButtons

I'm making a chessboard for a project and I have to use JButtons. I'm trying to just set the board up with a blank image I have for each tile, this is the code I have:
Driver
public class Driver
{
public static void main (String[] args)
{
new ChessBoard();
}
}
ChessSquare
import javax.swing.*;
import java.awt.*;
public class ChessSquare
{
public ImageIcon pieceImage;
/** The square's location */
private int xCoord;
private int yCoord;
/** Constructor for the squares */
public ChessSquare(ImageIcon thePieceImage, int theXCoord, int theYCoord)
{
pieceImage = thePieceImage;
xCoord = theXCoord;
yCoord = theYCoord;
}
public int getXCoord()
{
return xCoord;
}
public int getYCoord()
{
return yCoord;
}
}
ChessBoard
public class ChessBoard
{
public ChessBoard()
{
JFrame board = new JFrame();
board.setTitle("Chess Board!");
board.setSize(500,500);
board.setLayout(new GridLayout(8,8));
JPanel grid[][] = new JPanel[8][8];
ImageIcon empty = new ImageIcon("/pieces/EmptySquare.jpg");
for(int x = 0; x<8; x++)
{
for(int y = 0; y<8; y++)
{
ChessSquare s = new ChessSquare(empty, x, y);
JButton square = new JButton(s.pieceImage);
grid[x][y].add(square);
board.setContentPane(grid[x][y]);
}
}
board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
board.setVisible(true);
}
}
My code compiles fine but when I run it I get this error:
Exception in thread "main" java.lang.NullPointerException at
ChessBoard.(ChessBoard.java:23) at Driver.main(Driver.java:8)
I don't know what to do to fix this error. Thanks for any help :)
One of the likely causes is ImageIcon empty = new ImageIcon("/pieces/EmptySquare.jpg");...
The path of the image suggest that you are using embedded resources, but ImageIcon(String) treats the value as if it were a file, you can't do this with embedded resources, they aren't files.
Instead, you need to use something more like ImageIcon empty = new ImageIcon(getClass().getResource("/pieces/EmptySquare.jpg"));.
Personally, I'd recommend that you should be using ImageIO.read(getClass().getResource("/pieces/EmptySquare.jpg")) as this will throw an exception if the resource can not be loaded from some reason, rather then failing silently.
grid[x][y].add(square); also won't work, as you've not assigned anything to grid[x][y]
grid[x][y] = new JPanel();
grid[x][y].add(square);
Might work better, but I don't know why you're doing this, when doing something like...
JButton grid[][] = new JButton[8][8];
//...
grid[x][y] = square;
Would seem to be more logical for what you are trying to achieve...
Updated...
Instead of board.setContentPane(grid[x][y]); you should be using board.add(grid[x][y]);, other wise you will replace the content pane with the button...since there can only be a single content pane, you'll only get one button...
In grid[x][y].add(square); you are actually calling JPanel.add(), because each element in the array is a JPanel.
So the error is because grid[x][y] is still null you will get a NullPointerException if you call a method on it, like add() in this case.
You want to assign the value since you are using an array
grid[x][y] = square;

How to share same GCanvas in a GraphicsProgram in java?

I'm new at the Java world, and I started to take the Stanford cs106A course. I made the "breakout" problem which consists of making a simple breakout game.
I want to go even further, and my point is to create new Classes that can incorporate objects on the GCanvas of the main class.
So, now I have something like this:
public class Breakout extends GraphicsProgram {
//...
public void run();
private void playGame();
private void checkForPaddleCollisions();
private boolean passedBorderline();
private boolean moreBricksRemainig();
private void checkForCollisions();
private void updatePuntuation(GObject obj);
private void changeDirection(int temp);
private GObject getCollidingObject(double x, double y);
private void moveBall();
private void checkForBounderies();
private boolean hitsLeftWall();
private boolean hitsRightWall();
private boolean hitsRoof();
private void setRandomVx();
private void setBall();
private void setUp();
private void setLabels();
private void setPaddle();
public void mouseDragged (MouseEvent e);
public void mousePressed(MouseEvent i);
private void placeBricks();
private GOval ball;
private GRect paddle;
private GLabel win, lose, lifes, puntuationLabel;
private GPoint last;
private double vx, vy = 3.0;
private RandomGenerator rgen = RandomGenerator.getInstance();
private int Delay = 50;
private int counterBricks = NBRICKS_PER_ROW * NBRICK_ROWS;
private AudioClip bounceClip = MediaTools.loadAudioClip("bounce.au");
private int noPaddleBugs = 0;
private int puntuation = 0;
private int actualPunt = 0;
}
This is the main class of the game. What I want to do is to create a new class named PowerUps. This class can put any object on the GCanvas object of the main class at any point of the game. I tried to access the GCanvas of the main class by saying something like Breakout."canvasproperty".add(newObject), but it seems like it's not permitted.
Then I thought: I can create a class that extends GCanvas and then initialize a public property in the main class of that "new" canvas. With this method, I am able to insert new objects in this canvas from outer classes, but the problem is that when I run the Breakout class, the "new" canvas property doesn't show...
I don't know if I expressed myself well, but I tried, if anyone can help me, i would be very grateful?
Thanks in advance.

How to delete an JPanel Object?

Im on to create a little "game", something like an 2d AirForce Shooter.
So, i have a problem with deleting unused enemys.
An Enemy is an simple JPanel, which is saved in the main logic as an array List.
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
The Enemy run logic does the following:
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
So you can seem there i already tried to call the method deleteEnemy, and just give it the unused Enemy.
But it isnt possible - when i just do this:
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
It will be just removed from the list, but coninues existing on the Main JPanel.
And i cannot say
remove(e);
Because then i try to call a non static function in a static.
So, how could i delete an Enemy? Someone knows?
Thanks for help!
The hole code: (Game.java)
And, Enemy.java:
package Game;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
public class Field extends JPanel implements Runnable{
public static Player player = new Player();
public static ArrayList<Enemy> enemys = new ArrayList<Enemy>();
private Thread moveBackground = new Thread(this);
private boolean bgMoving = false;
public static boolean addMob = false;
private int x = 0;
private int bgSpeed = -1;
public Field(){
setBounds(0, 0, 800, 600);
setFocusable(true);
setLayout(null);
addKeyListener(new Handler());
add(player);
}
public void paintComponent(Graphics g){
Field.super.paintComponent(g);
g.drawImage(Images.images[0], x, 0, this);
}
public static void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
}
public void run(){
while(!Player.death){
if(bgMoving){
bgMoving = true;
x += bgSpeed;
if(x < -(Images.images[0].getWidth(this) - this.getWidth() - 20)){
bgMoving = false;
}
repaint();
try { Thread.sleep(20); } catch (InterruptedException e) {}
}
if(addMob){
enemys.add(new Enemy());
add(enemys.get(enemys.size() - 1));
addMob = false;
}
}
JOptionPane.showMessageDialog(null, "DIED!");
}
public class Handler extends KeyAdapter {
public void keyPressed(KeyEvent e) {
player.KeyPressed(e);
if(!bgMoving){
if(Game.running){
bgMoving = true;
if(moveBackground.getState().toString() == "NEW"){
moveBackground.start();
}
}
}
}
public void keyReleased(KeyEvent e) {
player.KeyReleased(e);
}
}
}
And, Enemy.java:
package Game;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class Enemy extends JPanel implements Runnable{
Thread t = new Thread(this);
private double x = Game.width();
private double y = Math.random() * Game.height();
private double xF = 0, yF = 0;
private boolean destroyed = false;
public Enemy(){
setBounds((int) x, (int) y, 100, 50);
setOpaque(false);
t.start();
}
public void paintComponent(Graphics g){
Enemy.super.paintComponent(g);
g.setColor(Color.GREEN);
g.drawImage(Images.images[2], 0, 0, this);
}
public void run() {
while(!destroyed){
if(Game.running){
x--;
if(getBounds().intersects(Field.player.getBounding())){
Player.death = true;
}
if(x < 0){
Field.deleteEnemy(this);
}
setBounds((int) x, (int) y, 100, 50);
try{Thread.sleep(10);}catch(InterruptedException e){}
}
}
}
}
After removing you will need to call revalidate() and repaint()
[Too long for a comment]
I think the problem is in your logic on removing an Enemy/JPanel:
You are removing it from the ArrayList only, what about the containing JPanel/JFrame you added it to?
You must remove the JPanel from its container (maybe another JPanel or the JFrame) not just the ArrayList via Component#remove(Component c).
If you drew the Enemy images directly in paintComponent(...) of your container via iterating the ArrayList; removing it from the ArrayList would be sufficient, as it will no longer be in the Array and thus no longer drawn on the next repaint().
+1 to #Optional, you may need to call revalidate() and repaint() on the container for the affects of the removed JPanel/Enemy to be shown.
Also as #darijan mentioned, the use of static variables along with instance is not really a great design (though for certain designs this may be fine).
In your case if you need access to an instance method of another class, within another class, simply pass the instance of the class whos method you would like to access to the object which will access it.
Here is some psuedo code expressing much of the above mentioned problems / solutions:
public class Field extends JPanel {
private ArrayList<Enemy> enemies;
public Field() {
...
enemies.add(new Enemy(this));//create a new enemy and pas it the JPanel instance so it may access instance methods of this class
}
//ONLY USED IF JPanel for Enemy is ommited and Enemy class created which represents Enemy object and not Enemy object and aJPanel
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
ArrayList<Enemy> enemiesClone = new ArrayList<>(enemies);//copy array into another so we don't get a ConcurrentModificaton exception if removeEnemy is called while iterating the list
if(!enemiesClone.isEmpty())
for(Enemy e:enemiesClone) {//iterate through array of images
draw(e.getImage(),e.getX(),e.getY(),this);
}
}
public void removeEnemy(Enemy e) {
enemies.remove(e);//remove from the array
//ONLY USED IF JPanels are used as Enemy
remove(e);//remove from the JPanel
//so the changes of removed panel can be visible seen
revalidate();
repaint();
}
}
class Enemy extends JPanel //extends JPanel should be ommited for paintComponent method of drawing an enemy onscreen
{
private int x,y;
private BufferedImage image;
private Field f;
public Enemy(Field f) {//constructor accepts Field instance to access instance method for the class
this.f=f;
}
public void update() {
if(offscreen||dead) {
f.removeEnemy(this);//call removeEnemy which is an instance method of Field
}
}
//BELOW METHODS ONLY USED WHEN Enemy represents object and not a JPanel which can draw its image itself (and update position by simply changing co-ordinates)
public BufferedImage getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
For a more detailed look check Game Development Loop, Logic and Collision detection Java Swing 2D I made which will give you the basics needed for most 2D games. However I do not use JPanels rather draw directly to a container.
Where do you add an Enemy to JPanel?
Basically, you should call remove on Field JPanel:
public void deleteEnemy(Enemy e){
System.out.println("test");
enemys.remove(e);
this.remove(e);
}
The method should not be static.

Categories