Travisty
Travisty

Reputation: 315

Only last JPanel ActionListeners working

I'm creating a menu for a game, and trying to create 4 JPanels, each with the ability to scroll through avatars that the player can use.

It works with one instance of the JPanel, but not more than one, and only the last JPanel will work. I think it must be to do with the creation of each component within the JPanels, but I can't figure it out.

I'll post the class below.

@SuppressWarnings("serial")
public class Menu extends JPanel implements ActionListener {

  JLabel playerAvatar;
  JLabel playerTxt;
  JButton playerPlus;
  JButton playerMinus;
  Font font_1 = new Font("calibri", Font.BOLD, 55);
  Font font_2 = new Font("calibri", Font.BOLD, 30);
  int playerAvatarCount = -1;

  public Menu() {
    init();
  }

  public void init() {
    setOpaque(false);
    setLayout(new FlowLayout());
    setPreferredSize(new Dimension(1000, 800));

    JPanel[] players = new JPanel[4];
    players[0] = playerChoose(1);
    players[1] = playerChoose(2);
    players[2] = playerChoose(3);
    players[3] = playerChoose(4);

    for (int i = 0; i < 4; i++) {
      add(players[i]);
    }
  }

  private JPanel playerChoose(int i) {
    JPanel plyrPanel = new JPanel();
    plyrPanel.setPreferredSize((new Dimension(240, 200)));
    plyrPanel.setOpaque(false);

    playerAvatar = new JLabel("", SwingConstants.CENTER);
    playerAvatar.setIcon(new ImageIcon("C:\\Users\\Travis\\workspace\\BoardGame\\none.png"));
    playerAvatar.setBackground(Color.WHITE);
    playerAvatar.setOpaque(true);
    playerAvatar.setBorder(BorderFactory.createLineBorder(Color.decode("#5B5C5C"), 3));
    playerAvatar.setPreferredSize(new Dimension(105, 155));

    playerPlus = new JButton(">");
    playerPlus.setPreferredSize(new Dimension(60, 155));
    playerPlus.setFont(font_1);
    playerPlus.setForeground(Color.decode("#5B5C5C"));
    playerPlus.setBorder(BorderFactory.createLineBorder(Color.decode("#5B5C5C"), 1));
    playerPlus.setBackground(Color.decode("#B2DBA4"));
    playerPlus.addActionListener(this);




    playerMinus = new JButton("<");
    playerMinus.setPreferredSize(new Dimension(60, 155));
    playerMinus.setFont(font_1);
    playerMinus.setForeground(Color.decode("#5B5C5C"));
    playerMinus.setBorder(BorderFactory.createLineBorder(Color.decode("#5B5C5C"), 1));
    playerMinus.setBackground(Color.decode("#B2DBA4"));
    playerMinus.addActionListener(this);

    playerTxt = new JLabel("Player " + i + "", SwingConstants.CENTER);
    playerTxt.setFont(font_2);
    playerTxt.setOpaque(false);
    playerTxt.setForeground(Color.WHITE);

    plyrPanel.add(playerMinus);
    plyrPanel.add(playerAvatar);
    plyrPanel.add(playerPlus);
    plyrPanel.add(playerTxt);
    validate();
    return plyrPanel;
  }

  @Override
  public void actionPerformed(ActionEvent e) {
      if (e.getSource() == playerPlus) {
        playerAvatar
            .setIcon(new ImageIcon("C:\\Users\\Travis\\workspace\\BoardGame\\frog" + ++playerAvatarCount + ".png"));
      }
      if (e.getSource() == playerMinus) {
        playerAvatar
            .setIcon(new ImageIcon("C:\\Users\\Travis\\workspace\\BoardGame\\frog" + --playerAvatarCount + ".png"));
      }

      if (playerAvatarCount < 0) {
        playerAvatar.setIcon(new ImageIcon("C:\\Users\\Travis\\workspace\\BoardGame\\none.png"));
        playerAvatarCount = -1;
      } else if (playerAvatarCount > 3) {
        playerAvatar.setIcon(new ImageIcon("C:\\Users\\Travis\\workspace\\BoardGame\\frog3.png"));
        playerAvatarCount = 3;
      }
    }
  }

Upvotes: 0

Views: 55

Answers (3)

Oliver Watkins
Oliver Watkins

Reputation: 13499

You really need to be object-oriented about this. Each one of these 4 menu elements is one type of class, and they all should have their own instance of their playerPlus and playerMinus button.

public class MenuElement extends JPanel {

    JLabel playerAvatar;
    JLabel playerTxt;
    JButton playerPlus;
    JButton playerMinus;

    public void initComponent() {
        //lay out your elements here
    }

    public void addListeners() {
        //setUpYour listeners here
    }

}

If you write a class like this then your menu element will have a reference to its own instance of the player plus and minus buttons. The problem you are having is that you have one instance of playerPlus and playerMinus which are being shared across four different components.

Upvotes: 2

Roel van Endhoven
Roel van Endhoven

Reputation: 180

This is because you define the JButtons as fields in your class. When you call playerChoose(int) you assign playerPlus and playerMinus to the reference of a new JButton. This happens for each time playerChoose is called. So, when the ActionListener compares the event source (e.getSource()) to the reference stored in playerPlus or playerMinus, only the last defined reference works, seeing as that is the last time playerPlus/playerMinus was set.

Upvotes: 0

StanislavL
StanislavL

Reputation: 57381

In your method you recreate buttons playerPlus = new JButton(">");

but then in the actionPerformed() you check source by comparing with the field

if (e.getSource() == playerPlus)

The field contains only the last created button so the conditions

if (e.getSource() == playerPlus)
if (e.getSource() == playerMinus)

are always false.

The simplest way would be to define name for the buttons and use the name in the checks

playerPlus = new JButton(">");
playerPlus .setName(">");

Then check would be

if (e.getSource() instanceof JButton && ">".equals(((JButton)e.getSource()).getName()) ) {
  //do your logic here
}

Upvotes: 1

Related Questions