使用removeActionListener但不删除 - JAVA

时间:2015-01-03 18:44:39

标签: java swing jbutton actionlistener

我已经创建了Tic-Tac-Toe游戏的一部分,我试图确保一旦游戏开始,“玩家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());
        }

      }
    }
  }

问题是,这不会禁用按钮

2 个答案:

答案 0 :(得分:4)

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

  • 首先,正如Christian指出的那样,你不是在添加和删除相同的实例。我不确定这是否可以通过给类等于和hashCode覆盖来缓解,我必须测试它。
  • 但更重要的是,当你似乎没有把它添加到任何按钮时,你似乎期望课堂的动作能够表现出来。我在哪里看到addActionListener(this)。话虽如此,我尽量避免使用我的GUI&#34;查看&#34;类实现了监听器接口。
  • 更好的解决方案可能是通过setAction(...)方法交换JButton AbstractActions。将AbstractActions想象为类固醇上的ActionListeners,因为它们可以执行ActionListener可以执行的所有操作,然后执行一些操作。这样做,你不必担心删除以前的听众,因为按钮只能有一个动作。

其他问题:

  • 您的程序严重过度使用静态修饰符。虽然静态字段和方法可能在小程序中不重要,但它们并不是一个很好的习惯,因为它们不会“缩放”#34;好。换句话说,如果你创建大而复杂的程序(如果你坚持使用Java,那么),过度使用静态字段和方法会增加潜在的复杂性并限制程序类的继承潜力,使它们变得非常困难调试或增强。避免过度使用静态修饰符是一个好习惯,除非在某些确实需要它的情况下。
  • 您正在将Swing GUI与控制台程序混合,这是一件危险的事情。更好的方法是通过GUI获取所有用户输入,并将控制台输出留给调试目的(如果那样)。

修改
是的,如果你重写equals和hashCode以便一个类型的所有监听器都是相同的,那么你可以在你尝试的时候删除它们。

例如,检查此测试代码:

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
我不认真读你的问题是个白痴。如果这是你的目标:

  

我正在努力确保&#34;播放器VS播放器&#34;一旦游戏开始,按钮就会被禁用:

然后,您只需将按钮或其操作设置为禁用即可。即,

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

答案 1 :(得分:1)

您应该使用相同的实例来调用添加和删除。 因此,将听众存储在一个字段中