简体   繁体   English

如何使用外部类实现ActionListener?

[英]How to implement ActionListener using an outer class?

When I implement ActionListener as an inner class of the registered listener class then it works fine but when I try to do that outside of the registered class, ie, outer class, then the button action does not work. 当我将ActionListener实现为已注册的侦听器类的内部类时,它可以正常工作,但是当我尝试在已注册的类(即外部类)之外进行操作时,则按钮操作无效。

Can anyone explain me why? 谁能解释我为什么? Or any suggestion to implement ActionListener as an outer class? 或有任何建议将ActionListener实现为外部类?

The code is below. 代码如下。 Thanks in advance. 提前致谢。

// MainMethod.java

import java.awt.Dimension;
import java.awt.Toolkit;

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

public class MainMethod
{
  public static void main(String[] args)
  {
    Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
    JFrame frame = new Framework("Tic Tac Toe", size.width / 4,
        size.height / 3, 950, size.height / 8);

    JPanel panel = new ButtonPanel();

    frame.getContentPane().add(panel);
    frame.setVisible(true);
  }
}


// ButtonPanel.java
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;

public class ButtonPanel extends JPanel
{
  private static final long serialVersionUID = -4829885180501818987L;
  JButton buttons[] = new JButton[9];

  ButtonPanel()
  {

    String name[] = { "button1", "button2", "button3", "button4", "button5",
        "button6", "button7", "button8", "button9" };

    Border lineBorder = new LineBorder(Color.black, 2);
    GridLayout panelLayout = new GridLayout(3, 3);
    setLayout(panelLayout);

    for (int i = 0; i < name.length; i++)
    {
      buttons[i] = new JButton(name[i]);
      buttons[i].setBackground(Color.white);
      buttons[i].setBorder(lineBorder);
      buttons[i].addActionListener(new ButtonActionListener());
      add(buttons[i]);
    }
  }

  // Inner class implementation
  class ButtonActionListener implements ActionListener
  {
    public void actionPerformed(ActionEvent ae)
    {

      if (ae.getActionCommand().equals("button1"))
      {
        buttons[0].setText("X");
      }
    }
  }
}

And following is the outer class implementation which doesn't work when used: 以下是外部类实现,该实现在使用时不起作用:

// ButtonActionListener.java
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class ButtonActionListener implements ActionListener
{
  public void actionPerformed(ActionEvent ae)
  {
    ButtonPanel buttonPanel = new ButtonPanel();
    if (ae.getActionCommand() == "button1")
    {
      buttonPanel.buttons[0].setText("X");
    }
  }
}

In your outer ButtonActionListener class, write something like the following: 在您的外部ButtonActionListener类中,编写类似以下内容的内容:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;

public class ButtonActionListener implements ActionListener
{
  public void actionPerformed(ActionEvent event)
  {
    if (event.getActionCommand().equals("button1"))
    {
      ((JButton) (event.getSource())).setText("X");
    }
  }
}

You can call the getSource() method to fetch the component which called this actionPerformed(ActionEvent) method, and then cast it to JButton , since we know its a ButtonActionListener , and then set its appropriate text. 您可以调用getSource()方法来获取调用此actionPerformed(ActionEvent)方法的ButtonActionListener ,然后将其ButtonActionListenerJButton ,因为我们知道它的ButtonActionListener ,然后设置其适当的文本。

UPDATE: 更新:

Here's a demonstration of how to use outer ActionListener class: 这是如何使用外部ActionListener类的演示:

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class Demo
{
  public static final String BUTTON_1 = "Demo.BUTTON_1";
  public static final String BUTTON_2 = "Demo.BUTTON_2";

  public Demo()
  {
    JFrame frame = new JFrame("Outer ActionListener");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout(new FlowLayout(FlowLayout.CENTER));

    ButtonActionListener buttonActionListener = new ButtonActionListener();

    JButton button1 = new JButton("Button 1");
    button1.setActionCommand(Demo.BUTTON_1);
    button1.addActionListener(buttonActionListener);

    JButton button2 = new JButton("Button 2");
    button2.setActionCommand(Demo.BUTTON_2);
    button2.addActionListener(buttonActionListener);

    frame.add(button1);
    frame.add(button2);

    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setResizable(false);
    frame.setVisible(true);
  }

  public static void main(String[] args)
  {
    // Doing this because Swing is not thread safe.
    SwingUtilities.invokeLater(new Runnable()
    {
      @Override
      public void run()
      {
        new Demo();
      }
    });
  }
}

class ButtonActionListener implements ActionListener
{
  @Override
  public void actionPerformed(ActionEvent event)
  {
    String actionCommand = event.getActionCommand();

    // Since Java 7, String can be used in switch statements
    switch (actionCommand)
    {
      case Demo.BUTTON_1:
        System.out.println("Button 1 is clicked.");
        break;

      case Demo.BUTTON_2:
        System.out.println("Button 2 is clicked.");
        break;

      default:
        System.out.println("I don't know!");
        break;
    }
  }
}

Hope your doubts are clear by now. 希望您的疑问现在已经清除。

By the way, you can also use Anonymous Inner classes for adding listeners on components, and since JDK 8, Lambda Expressions. 顺便说一句,您还可以使用Anonymous Inner类来添加组件上的侦听器,并且自JDK 8开始,使用Lambda Expressions。 You can search how those things are done online (if you're interested to know other ways of implementing the same thing). 您可以搜索这些事情如何在线完成(如果您想了解实现同一件事的其他方法)。

You're creating a new ButtonPanel object inside of your outer ActionListener. 您正在外部ActionListener中创建一个新的ButtonPanel对象。 This new ButtonPanel object is completely distinct from the one that is being displayed and interacting with the user. 这个新的ButtonPanel对象与正在显示并与用户交互的对象完全不同。

A solution: pass in a reference to the true ButtonPanel instance into your outer listener via the listener's constructor. 一个解决方案:通过侦听器的构造函数将对真正的ButtonPanel实例的引用传递到外部侦听器中。

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

class ButtonActionListener implements ActionListener
{
  private ButtonPanel buttonPanel;

  public ButtonActionListener(ButtonPanel buttonPanel)
  {
    this.buttonPanel = buttonPanel;
  }

  public void actionPerformed(ActionEvent actionEvent)
  {
    // ButtonPanel bp=new ButtonPanel();
    if (actionEvent.getActionCommand().equals("button1"))
    {
      buttonPanel.buttons[0].setText("X");
    }
  }
}

Then you can set this up via: 然后,您可以通过以下方式进行设置:

buttons[i].addActionListener(
    new ButtonActionListener(/*pass in the valid ButtonPanel reference here*/));

Another and better option is to link the buttons to a Model object, give your control a reference to the Model object and have it make method calls on the model or notification calls on its model listeners. 另一个更好的选择是将按钮链接到Model对象,为控件提供对Model对象的引用,并让其对模型进行方法调用或对其模型侦听器进行通知调用。

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

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