-1

I'm building a swing based GUI for a Java game. The game is essentially a 4x4 grid made up of custom Cell objects, which is in essence, a custom JButton. Code for this below

package gamePack;
import java.awt.Graphics;
import java.util.ArrayList;

import javax.swing.JButton;

public class Cell extends JButton {

int co_x = 0;
int co_y = 0;

  ArrayList<Players> current = new ArrayList <Players>();
}

The ArrayList allows me to store Objects of different Players. All the Players inherit from the same class, so I'm essentially redrawing the cell and adding Icons based on the type of object within the ArrayList. There is an ArrayList for each cell as each cell can have multiple Players.

GUI initialization:
package gamePack;

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.border.Border;

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class StarFight {

    public JFrame frame;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    StarFight window = new StarFight();
                    window.frame.setVisible(true);


                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * Create the application.
     */
    public StarFight() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setVisible(true);
        frame.setBounds(100, 100, 487, 349);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().setLayout(null);

        final JPanel gamePanel = new JPanel();
        gamePanel.setBounds(0, 0, 365, 310);
        frame.getContentPane().add(gamePanel);
        int i = 4;
        int j = 4;
        final Cell[][] panelHolder = new Cell[i][j]; 
        gamePanel.setLayout(new GridLayout(4, 4, 0, 0));
        //91.25 x 77.5 rectangles

        Border border = BorderFactory.createLineBorder(Color.white);
        for(int m = 0; m < i; m++) {
            for(int n = 0; n < j; n++) {
                panelHolder[m][n] = new Cell();
                panelHolder[m][n].co_x = m;
                panelHolder[m][n].co_y= n;
                panelHolder[m][n].setBackground(Color.black);
                panelHolder[m][n].setEnabled(false);
                panelHolder[m][n].setBorder(border);
                gamePanel.add(panelHolder[m][n]);

            }
        }


        JPanel controlPanel = new JPanel();
        controlPanel.setBounds(375, 0, 86, 310);
        frame.getContentPane().add(controlPanel);
        controlPanel.setLayout(null);

        final JButton Move = new JButton("Move");
        Move.setEnabled(false);
        Move.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                panelHolder[0][0].current.clear();
                BattleCruiser q = new BattleCruiser();
                panelHolder[3][2].current.add(q);

                Redraw.draw(gamePanel, panelHolder);
            }
        });
        Move.setBounds(1, 82, 84, 65);
        controlPanel.add(Move);

        final JButton Undo = new JButton("Undo");
        Undo.setEnabled(false);
        Undo.setBounds(1, 158, 84, 65);
        controlPanel.add(Undo);

        JButton Exit = new JButton("Exit");

        Exit.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                System.exit(0);
            }
        });
        Exit.setBounds(1, 234, 84, 65);
        controlPanel.add(Exit);

        final JButton btnStart = new JButton("Start");
        btnStart.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent arg0) {
                Move.setEnabled(true);
                Undo.setEnabled(true);
                btnStart.setEnabled(false);

                PlayChar p = new PlayChar();
                BattleCruiser q = new BattleCruiser();
                BattleStar s = new BattleStar();
                BattleShooter sh = new BattleShooter();

                panelHolder[0][0].current.add(p);


                Redraw.draw(gamePanel, panelHolder);
            }
        });
        btnStart.setBounds(1, 6, 84, 65);
        controlPanel.add(btnStart); 
    }
    }

The game changes when the Move button is clicked. Here, I'm adding in the player's sprite when I click start, and the redraw method is called. The redraw method below:

package gamePack;

import java.awt.Color;
import java.awt.GridLayout;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.Border;


public class Redraw {



    public static void draw(JPanel gamePanel, Cell[][] panelHolder ){


        gamePanel.setBounds(0, 0, 365, 310);

        int i = 4;
        int j = 4;

        gamePanel.setLayout(new GridLayout(4, 4, 0, 0));
        //91.25 x 77.5 rectangles



        Border border = BorderFactory.createLineBorder(Color.white);
        for(int m = 0; m < i; m++) {
            for(int n = 0; n < j; n++) {
                panelHolder[m][n].setBackground(Color.black);
                panelHolder[m][n].setEnabled(false);
                panelHolder[m][n].setBorder(border);
                panelHolder[m][n].setIcon(null);

                for(Players p: panelHolder[m][n].current){
                    if(p instanceof PlayChar){
                        String arg = "Player.png";
                        ImageIcon icon = new ImageIcon(arg); 
                        JLabel label = new JLabel(); 
                        label.setIcon(icon); 
                        panelHolder[m][n].add(label);

                    } else if (p instanceof BattleStar) {
                        String arg = "BattleStar.png";
                        ImageIcon icon = new ImageIcon(arg); 
                        JLabel label = new JLabel(); 
                        label.setIcon(icon); 
                        panelHolder[m][n].add(label);
                    }   else if (p instanceof BattleCruiser){
                        String arg = "BattleCruiser.png";
                        ImageIcon icon = new ImageIcon(arg); 
                        JLabel label = new JLabel(); 
                        label.setIcon(icon); 
                        panelHolder[m][n].add(label);
                    } else if (p instanceof BattleShooter){
                        String arg = "BattleShooter.png";
                        ImageIcon icon = new ImageIcon(arg); 
                        JLabel label = new JLabel(); 
                        label.setIcon(icon); 
                        panelHolder[m][n].add(label);
                    } 
                }
            }
        }
        gamePanel.revalidate();
        gamePanel.repaint();
    }
}

The redraw method checks the ArrayList in each cell, and then adds an icon appropriately. At the moment, when I click Move, it should remove all the JButtons, then add them back with the appropriate sprites.

The problem is that when I do so, even with the current.clear() before adding another sprite, the sprite in the 0,0 position is still drawn. Stepping through the code shows that the if statement for the PlayChar object isn't being called, so I have to assume that it's something to do with the redraw method. Am I doing something obviously wrong?

EDIT: Based on feedback, I have now changed it so the redraw function doesn't replace the JButtons, but changes their properties. I've also added it so that the Icon is set to null for each one before any Icons are set, to ensure that it is removed. The same problem, however, is still occurring

Jordan Moffat
  • 337
  • 6
  • 17
  • whatever.setIcon(null);, don' to replace JComponents at runtime to use, to change its properties by using setIcon/Border/background ... – mKorbel May 25 '15 at 16:27
  • @mKorbel ok, so i've edited the code so that it's not replacing the components, but is changing them, and added in the `setIcon(null);` to run before it attempts to change the icon to something else. However, it's still causing the same problems. – Jordan Moffat May 25 '15 at 16:47
  • 2
    is there a reason why you are using a JLabel and calling add to set the icon on a JButton instead of using .setIcon(icon) directly. – faljbour May 25 '15 at 19:38
  • *"which is in essence, a custom JButton"* Use a standard (possibly undecorated) `JButton` with an `ActionListener`. It will work for keyboard as well as mouse. – Andrew Thompson May 26 '15 at 00:01
  • `frame.getContentPane().setLayout(null);` Java GUIs have to work on different OS', screen size, screen resolution etc. using different PLAFs in different locales. As such, they are not conducive to pixel perfect layout. Instead use layout managers, or [combinations of them](http://stackoverflow.com/a/5630271/418556) along with layout padding and borders for [white space](http://stackoverflow.com/a/17874718/418556). – Andrew Thompson May 26 '15 at 01:35

1 Answers1

0

Problem found! Thanks to @faljbour

is there a reason why you are using a JLabel and calling add to set the icon on a JButton instead of using .setIcon(icon) directly?

This was the problem. The image was being set as a JLabel, which was then being added, so removing the Icon was having no effect.

Code should read:

String arg = "Player.png";
ImageIcon icon = new ImageIcon(arg);  
panelHolder[m][n].setIcon(icon); 
Jordan Moffat
  • 337
  • 6
  • 17