简体   繁体   English

使用removeActionListener但不删除-JAVA

[英]Using removeActionListener but not removing - JAVA

I have created part of a Tic-Tac-Toe game, and I am trying to make sure the "Player VS Player" button becomes disabled once a game is started. 我已经创建了Tic-Tac-Toe游戏的一部分,并且我试图确保一旦开始游戏,“ Player VS Player”按钮将被禁用。 I am new to Java swing and all of the graphics, so please, any help is appreciated. 我对Java swing和所有图形都是陌生的,因此,请提供任何帮助。 I have used .removeActionListener, but it seems to not do anything (or anything I notice). 我使用了.removeActionListener,但似乎什么也没做(或我注意到的任何事情)。 My code probably looks very bad to some of you, but as I said, I am new to this. 我的代码对某些人来说可能看起来很糟糕,但是正如我所说,我对此并不陌生。 Some of the imports may not be needed now, but I plan on using them later. 现在可能不需要某些导入,但是我计划以后再使用它们。 Thanks in advance! 提前致谢!

import java.util.Scanner;
import java.lang.Object;
import java.awt.Component;
import java.awt.Container;
import java.awt.Window;
import java.awt.Frame;
import javax.swing.JFrame;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.text.JTextComponent;
import javax.swing.JTextField;
import java.lang.Thread;
import java.util.EventObject;
import java.awt.AWTEvent;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowEvent;
import java.awt.Font;
import javax.swing.*;

class ticTacToe implements ActionListener
{
  public static JFrame menuFrame = new JFrame("Tic-Tac-Toe");
  public static JPanel menu = new JPanel();
  public static JButton instruct = new JButton("Instructions"), pvp = new JButton("Player VS. Player"), pvc = new JButton("Player VS. Computer");
  public static String pOne = "bla", pTwo = "bla";
  public static boolean namesEntered = false;
  public static JFrame pvpFrame = new JFrame (pOne+" "+"VS."+" "+pTwo);
  public static JPanel board = new JPanel (), turns = new JPanel();
  public static JLabel turn1 = new JLabel (pOne+" has taken 0 turn(s)."), turn2 = new JLabel (pTwo+" has taken 0 turn(s).");
  public static JButton btn1 = new JButton (), btn2 = new JButton (), btn3 = new JButton (), btn4 = new JButton (), btn5 = new JButton (), btn6 = new JButton (), btn7 = new JButton (), btn8 = new JButton (), btn9 = new JButton ();
  public static int choice = 3;
  public static Font f = new Font("Arial", Font.PLAIN, 40);

  public static void main (String[]args)
  {
    instruct.addActionListener(new Instructions());
    pvp.addActionListener(new playerVSPlayer());
    pvc.addActionListener(new Action());
    menu();
  }

  public static void menu ()//the main menu of the game
  {
    menu.setLayout(new FlowLayout());//arranges the layout of the buttons on the panel

    menu.add(instruct);//adds the instruction button
    menu.add(pvp);//adds the player vs player button
    menu.add(pvc);//adds the player vs computer button

    menuFrame.add(menu);//creates the panel
    menuFrame.setSize(450, 78);
    menuFrame.setLocationRelativeTo(null);//sets the location to the centre of the screen
    menuFrame.setVisible(true);//makes the menu visible
    menuFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//extis program when window is closed
  }
  public void actionPerformed (ActionEvent e)//detection of the clicked button
  {
    if (e.getSource().equals(instruct))
    {
      instructions();
    }
    else if (e.getSource().equals(pvp))
    { 
      if (e.getSource().equals(btn1))
      {
        btn1.setFont(f);
        btn1.setText("X");
        btn1.removeActionListener(new playerVSPlayer());
      }
      else
      {
        players();
        if (!pOne.equals("0")&&!pTwo.equals("0"))
        {
          firstTurn();
        }
        if (namesEntered==true&&choice==1)
        {
          gameBoard();
          btn1.addActionListener(new playerVSPlayer());
        }
        pvp.removeActionListener(new playerVSPlayer());
      }
    }
  }

  public static void instructions ()
  {
    JFrame frame = new JFrame ("Instructions");
    frame.setVisible(true);
    frame.setSize(300,145);
    JLabel label = new JLabel ("The goal of this game is to be the first player that ");
    JLabel label2 = new JLabel ("gets 3 X's or O's in a row diagonally, vertically, or");
    JLabel label3 = new JLabel ("horizontally. It is possible to tie, by having all");
    JLabel label4 = new JLabel ("spaces played with no spots left to win. Click a");
    JLabel label5 = new JLabel ("space to enter your X or O.");
    JPanel panel = new JPanel();
    panel.setLayout(new FlowLayout());
    frame.add(panel);
    panel.add(label);
    panel.add(label2);
    panel.add(label3);
    panel.add(label4);
    panel.add(label5);
  }

  public static void players ()
  {
    Scanner in = new Scanner (System.in);
    System.out.println("Player One, please enter a word no longer than 4 letters, representing your username for this game.");
    pOne = in.nextLine();
    if (pOne.equals("0"))
    {
      System.out.println("You have cancelled the match. Please choose an option in the main menu, or close the main menu.");
    }
    else {
      while (pOne.length()>4||pOne.length()<1)
      {
        System.out.println("Player One, your username MUST be between 1 and 4 letters long.");
        pOne = in.nextLine();
      }
    }
    if (!pOne.equals("0"))
    {
      System.out.println("Player Two, please enter a word no longer than 4 letters, representing your username for this game.");
      pTwo = in.nextLine();
      if (pTwo.equals("0"))
      {
        System.out.println("You have cancelled the match. Please choose an option in the main menu, or close the main menu.");
      }
      else {
        while (pTwo.length()>4||pTwo.length()<1)
        {
          System.out.println("Player Two, your username MUST be between 1 and 4 letters long.");
          pTwo = in.nextLine();
        }
      }
    }
    if (!pOne.equals("0")&&!pTwo.equals("0"))
    {
      namesEntered= true;
    }
  }
  public static void gameBoard ()
  {
    pvpFrame = new JFrame (pOne+" "+"VS."+" "+pTwo);
    pvpFrame.setLayout(new GridLayout());
    pvpFrame.setVisible(true);
    pvpFrame.setSize(600,400);
    pvpFrame.setLocationRelativeTo(null);
    board.setLayout(new GridLayout(3,3));
    turns.setLayout(new FlowLayout());
    pvpFrame.add(board);
    pvpFrame.add(turns);
    turn1 = new JLabel (pOne+" has taken 0 turns.");
    turn2 = new JLabel (pTwo+" has taken 0 turns.");
    turns.add(turn1);
    turns.add(turn2);
    board.add(btn1);
    board.add(btn2);
    board.add(btn3);
    board.add(btn4);
    board.add(btn5);
    board.add(btn6);
    board.add(btn7);
    board.add(btn8);
    board.add(btn9);
  }

  public static void firstTurn ()
  { 
    Scanner in = new Scanner (System.in);
    System.out.println(pOne+" will be X and "+pTwo+" will be O. Enter 1 if you would like to continue. Enter 0 if you would like to cancel this match and return to the main menu.");
    choice = in.nextInt();
    while (choice!=0&&choice!=1)
    {
      System.out.println("Your choice did not match 1 or 0. Please enter your choice again.");
      choice = in.nextInt();
    }
    if (choice==0)
    {
      System.out.println("You have cancelled the match. Please choose an option in the main menu, or close the main menu.");
    }
  }
}

EDIT 1: 编辑1:

 public void actionPerformed (ActionEvent e)//detection of the clicked button
  {
    if (e.getSource().equals(instruct))
    {
      instructions(); // This just runs the instruction panel
    }
    else if (e.getSource().equals(pvp))
    { 
      if (e.getSource().equals(btn1))
      {
        btn1.setFont(f);
        btn1.setText("X");
        btn1.removeActionListener(new playerVSPlayer());
      }
      else
      {
        players();
        if (!pOne.equals("0")&&!pTwo.equals("0"))
        {
          firstTurn();
        }
        if (namesEntered==true&&choice==1)
        {
          gameBoard();
          pvp.setEnabled(false); // my goal here is to make the button no longer usable once the 
//game starts, but I also need to make sure later that i can use the button once this game is closed
          btn1.addActionListener(new playerVSPlayer());
        }

      }
    }
  }

The problem is, that does not disable the button 问题是,这不会禁用按钮

I have several issues with your code, but as far as your question is concerned, there are two main issues: 我的代码有几个问题,但是就您的问题而言,有两个主要问题:

  • First as Christian points out, you are not adding and removing the same instance. 首先,正如克里斯蒂安(Christian)所指出的,您没有添加和删除同一实例。 I'm not sure if this can be alleviated by giving the class an equals and hashCode override, and I must test this. 我不确定是否可以通过给类一个equals和hashCode重写来缓解这种情况,我必须对此进行测试。
  • But even more important, you seem to expect the class's actionPerformed to act, when you don't appear to add it to any buttons. 但更重要的是,您似乎希望类的actionPerformed在您未将其添加到任何按钮时起作用。 No where do I see addActionListener(this) . 在哪里看不到addActionListener(this) Having said that, I try to avoid making my GUI "view" classes implement listener interfaces. 话虽如此,我试图避免使我的GUI“视图”类实现侦听器接口。
  • A better solution perhaps would be swapping JButton AbstractActions via the setAction(...) method. 更好的解决方案可能是通过setAction(...)方法交换JButton AbstractActions。 Think of AbstractActions as if they were ActionListeners on steroids, since they can do everything that an ActionListener can do and then some. 可以将AbstractAction视为类固醇上的ActionListener,因为它们可以执行ActionListener可以执行的所有操作,然后执行某些操作。 Do this and you won't have to worry about removing prior listeners since a button can have one and only one Action. 这样做,您将不必担心删除以前的侦听器,因为一个按钮可以只有一个动作。

Other issues: 其他事宜:

  • Your program grossly over-uses the static modifier. 您的程序严重使用了static修饰符。 While static fields and methods probably won't matter in small programs, they're not a good habit to get into since they don't "scale" well. 尽管静态字段和方法在小型程序中可能无关紧要,但由于它们无法“很好地”扩展,因此它们不是一种好习惯。 In other words, if you create large and complex programs (and if you stick with Java, you will), over-use of static fields and methods increases the potential complexity and limits the inheritance potential of your classes of your programs making them very difficult to debug or enhance. 换句话说,如果您创建大型而复杂的程序(如果您坚持使用Java,则可以),则过多使用静态字段和方法会增加潜在的复杂性并限制程序类的继承潜力,从而使它们非常困难调试或增强。 It's a good habit to avoid over-use of static modifier except in the certain situations where it is definitely called for. 避免过度使用static修饰符是一个好习惯,除非在某些情况下确实需要使用它。
  • You're mixing a Swing GUI with a console program which is a dangerous thing to do. 您正在将Swing GUI与控制台程序混合使用,这是很危险的事情。 Much better would be to get all user input via the GUI, and leave the console output for debugging purposes (if that) only. 更好的办法是通过GUI获取所有用户输入,并将控制台输出仅用于调试目的(如果有的话)。

Edit 编辑
Yep, if you override equals and hashCode so that all Listeners of one type are the same, then you can remove them as you're trying to do. 是的,如果您覆盖equals和hashCode以便一种类型的所有侦听器都相同,则可以在尝试执行操作时将其删除。

For example check this test code: 例如,检查以下测试代码:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class TestActionListeners extends JPanel {
   private JButton button = new JButton("Button");

   public TestActionListeners() {
      add(button);

      button.addActionListener(new Listener1());
   }

   private static void createAndShowGui() {
      TestActionListeners mainPanel = new TestActionListeners();

      JFrame frame = new JFrame("Test");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class Listener1 implements ActionListener {
   @Override
   public void actionPerformed(ActionEvent e) {
      System.out.println("in listener 1");

      AbstractButton button = (AbstractButton) e.getSource();

      button.removeActionListener(new Listener1());
      button.addActionListener(new Listener2());
   }

   @Override
   public boolean equals(Object obj) {
      return obj instanceof Listener1;
   }

   @Override
   public int hashCode() {
      return Listener1.class.hashCode();
   }
}

class Listener2 implements ActionListener {
   @Override
   public void actionPerformed(ActionEvent e) {
      System.out.println("in listener 2");

      AbstractButton button = (AbstractButton) e.getSource();

      button.removeActionListener(new Listener2());
      button.addActionListener(new Listener1());
   }

   @Override
   public boolean equals(Object obj) {
      return obj instanceof Listener2;
   }

   @Override
   public int hashCode() {
      return Listener2.class.hashCode();
   }
}

Having said this, I don't recommend that you do this but rather swap AbstractActions via setAction(...) . 话虽如此,我不建议您这样做,而是通过setAction(...)交换AbstractActions。


Edit 2 编辑2
I'm an idiot for not carefully reading your question. 我是个白痴,没有认真阅读您的问题。 If this is your goal: 如果这是您的目标:

and I am trying to make sure the "Player VS Player" button becomes disabled once a game is started: 并且我正在尝试确保在游戏开始后禁用“玩家VS玩家”按钮:

Then all you need to do is set the button or its Action disabled. 然后,您所需要做的就是设置按钮禁用其“操作” ie,

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;

public class DisableAButton extends JPanel {
   private JButton disableMeButton1 = new JButton("Disable Me 1");
   private JButton disableMeButton2 = new JButton(new DisableMe2Action("Disable Me 2"));

   public DisableAButton() {
      disableMeButton1.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            AbstractButton buttonSource = (AbstractButton) e.getSource();
            JOptionPane.showMessageDialog(buttonSource, "DisableMe1 ActionListener!");

            buttonSource.setEnabled(false);
         }
      });

      add(disableMeButton1);
      add(disableMeButton2);
   }

   private static void createAndShowGui() {
      DisableAButton mainPanel = new DisableAButton();

      JFrame frame = new JFrame("DisableAButton");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class DisableMe2Action extends AbstractAction {
   public DisableMe2Action(String name) {
      super(name);
   }

   @Override
   public void actionPerformed(ActionEvent e) {
      JComponent source = (JComponent) e.getSource();
      JOptionPane.showMessageDialog(source, "DisableMe2 Action!");

      setEnabled(false);
   }
}

you should use the same instance to call add and remove. 您应该使用同一实例来调用添加和删除。 therefor store the listeners in a field 因此将听众存储在一个字段中

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM