java - 使用 removeActionListener 但不删除 - JAVA

标签 java swing jbutton actionlistener

我已经创建了井字游戏的一部分,并且我试图确保在游戏开始后禁用“玩家 VS 玩家”按钮。我是 Java swing 和所有图形的新手,所以请提供任何帮助。我使用了 .removeActionListener,但它似乎什么也没做(或我注意到的任何事情)。我的代码对你们中的一些人来说可能看起来很糟糕,但正如我所说,我是新手。现在可能不需要某些导入,但我计划稍后使用它们。 提前致谢!

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.");
    }
  }
}

编辑 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());
        }

      }
    }
  }

问题是,这并没有禁用按钮

最佳答案

我对你的代码有几个问题,但就你的问题而言,主要有两个问题:

  • 首先,正如 Christian 所指出的,您添加和删除的不是同一个实例。我不确定是否可以通过为类提供 equals 和 hashCode 覆盖来缓解这种情况,我必须对此进行测试。
  • 但更重要的是,当您似乎没有将它添加到任何按钮时,您似乎期望类的 actionPerformed 起作用。我在哪里看不到 addActionListener(this)。话虽如此,我尽量避免让我的 GUI“ View ”类实现监听器接口(interface)。
  • 更好的解决方案可能是通过 setAction(...) 方法交换 JButton AbstractActions。将 AbstractActions 想象成类固醇的 ActionListeners,因为它们可以做 ActionListener 可以做的所有事情,然后再做一些。这样做,您就不必担心会移除先前的监听器,因为一个按钮只能有一个操作。

其他问题:

  • 您的程序严重过度使用了静态修饰符。虽然静态字段和方法在小程序中可能无关紧要,但养成它们并不是一个好习惯,因为它们不能很好地“扩展”。换句话说,如果您创建大型和复杂的程序(如果您坚持使用 Java,您会的),过度使用静态字段和方法会增加潜在的复杂性并限制您的程序类的继承潜力,使它们变得非常困难调试或增强。避免过度使用 static 修饰符是一个好习惯,除非在某些情况下绝对需要它。
  • 您将 Swing GUI 与控制台程序混合在一起,这是一件危险的事情。更好的做法是通过 GUI 获取所有用户输入,而将控制台输出仅用于调试目的(如果有的话)。

编辑
是的,如果您覆盖 equals 和 hashCode 以便一种类型的所有 Listener 都相同,那么您可以在尝试时删除它们。

例如检查这个测试代码:

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();
   }
}

话虽如此,我不建议您这样做,而是建议您通过 setAction(...) 交换 AbstractActions。


编辑2
我是个白痴,没有仔细阅读你的问题。如果这是您的目标:

and I am trying to make sure the "Player VS Player" button becomes disabled once a game is started:

然后您需要做的就是将按钮或其操作设置为禁用。即,

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);
   }
}

关于java - 使用 removeActionListener 但不删除 - JAVA,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27758284/

相关文章:

Java nio 在选择器上读取 SocketChannel

java - java如何存储文字?

java - 在java中将UTC日期和时间添加到数据库

java - 在 JToggleButton 中保存选择

java - 我如何每 10 秒显示一个字符串中的一个随机单词?

Java Swing - 带有三个点的组合框

java - 将特定于操作系统的窗口渲染到 BufferedImage

Java - JButton 监听器未触发

java - 如何在按下按钮时循环播放声音并在释放时停止播放?

java - 当另一个 JButton 被按下时添加一个 JButton