3

我有一个大表,每个单元格中都有一个按钮。这些按钮非常相似,功能几乎相同。如果我以这种方式为每个按钮添加一个动作监听器:

tmp.addActionListener(new ActionListener(){
   @Override
   public void actionPerformed(ActionEvent evt) {
      proposition = proposition + action;
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            updatePropositionPanel();
         }
      });
   }
});

实际上,每个动作侦听器与所有其他侦听器的不同之处在于action. proposition并且updatePropositionPanel是类的一个字段和一个方法。

  1. 首先,我认为如果我不使用内部类,我可以让它更短。所以,我决定编写一个新的 ActionListener 类。但我意识到,在这种情况下,“命题”对这个类的实例是不可见的。

  2. 然后我决定将 actionPerformed 方法添加到当前类并这样做addActionListener(this):但是我意识到我不知道如何为 actionPerformed 方法提供参数。

那么它是怎样工作的。我可以以一种简短而优雅的方式添加一个动作监听器吗?

添加:

我喜欢用构造函数编写内部类的想法,该构造函数可以接受一些参数和 actioPerformed 方法,该方法可以使用构造函数中给出的参数。我开始这样做,然后意识到它会与其他内部匿名类产生冲突(就像上面给定的代码一样使用)。所以,我想我会创建另一个类(不是内部类)。

4

8 回答 8

4

您可以创建自己的类并将数据传递给构造函数。例如

public class MyActionListener
{
    private int proposition;
    private MyOtherClass moc;

    public MyActionListener(int proposition, MyOtherClass moc) {
        this.proposition = proposition;
        this.moc = moc;
    }

    public void actionPerformed(ActionEvent evt) {
        proposition += moc.action;
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                moc.updatePropositionPanel();
            }
        });
    }
}

然后您可以正常添加它,将您喜欢的任何参数传递给构造函数:

tmp.addActionListener( new MyActionListener(proposition, this) );
于 2010-03-25T13:00:02.113 回答
1

编辑:我已经更改了类以使用 MyOuterClass 显示构造。

这是一些草拟的代码。希望这能达到你的 1,这就是我将如何实现它。

public class MyOuterClass {
    // member variables for MyOuterClass

    public MyOuterClass() {
        // ...constructor stuff here
    }
    // ...outer class stuff here - methods, etc.

    // The code each place you want to add the listener, somewhere in MyOuterClass
    tmp.addActionListener(new MyActionListener(poposition, action));


    // below outer class stuff, although it can really be most places, I usually put
    // it here - personal style preference.  Swing's classes often put inner
    // classes first

    /**
     * An inner class.
     */
    private MyActionListener implements ActionListener {
        /**
      * Object used here as a filler, replace with appropriate
      * class types
      */
        private Object proposition;
        private Object action;

        private MyActionListener(Object proposition, Object action) {
            this.proposition = proposition;
            this.action = action;
        }
        public void actionPerformed(ActionEvent evt) {
          proposition = proposition + action;
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                updatePropositionPanel();
             }
        }
        /**
         * Setters provided in case you need to change proposition and action.  If not,
         * feel free not to have them and to have final members
         */
        private void setProposition(Object proposition) {
            this.proposition = proposition;
        }
        private void setAction(Object action) {
            this.action = action;
        }
    }
}

编辑:要按照您在编辑中的要求创建另一个类,请执行上述操作,但在另一个 .java 文件中创建一个非私有的其他类并编写代码。

于 2010-03-25T13:00:19.100 回答
1

因为唯一的不同在于action你可以将代码放在一个方法中。(@Override 也是不必要的,+=在这里很有用。)

public void setup(
    final AbstractButton button,
    final int action
) { 
    button.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent evt) {
            proposition += action;
            EventQueue.invokeLater(new Runnable() {
                public void run() {
                   updatePropositionPanel();
                }
           });
        }
    });
}

invokeLater可能毫无意义,因为无论如何您都将使用 AWT 事件调度线程 (EDT)。

如果您要添加许多通用操作,那么您可以通过使用没有与之关联的无意义事件对象的接口来简化它。

如果你想变得 hackish,你可以在子类构造函数中添加监听器。

    new ActionHandler(button) { public void action() {
        proposition += action;
        updatePropositionPanel();
    }});

希望 JDK7 将使此类事物的 Java 语法不那么冗长。然而,Java 总是有些冗长。

于 2010-03-25T18:51:58.197 回答
0

如果您使proposition可变(例如StringBuilder,而不是String),选项 1 有效。如果您声明它们,则选项 2 有效final。这样它们就可以在内部类中访问/可见。

于 2010-03-25T12:53:01.563 回答
0

您可以创建一个单独的 MyActionListener 类,并使用构造函数传递两个值命题和动作。它整理了源代码。

于 2010-03-25T12:54:42.980 回答
0

您可以创建自己的实现 ActionListener 的侦听器类。此类可能包含与您正在谈论的参数相对应的成员变量;您将使用构造函数设置它们。

添加侦听器的调用将如下所示:

tmp.addActionListener(new MyActionListenerSubClass(proposition, action));
于 2010-03-25T12:55:02.777 回答
0

为了这个例子,我假设你的命题和动作变量是字符串。定义一个接口 PropositionUpdater、一个接口 PropositionPanelUpdater 和一个协作者命题持有者:

public interface PropositionUpdater() {
    public void updateProposition(PropositionHolder holder, String action);
}

public interface PropositionHolder() {
    public String getProposition();

    public void setProposition(String proposition);
}

public interface PropositionPanelUpdater() {
    public void updatePropositionPanel();
}

命题更新器的默认实现是这样的:

public class DefaultPropositionUpdater implements PropositionUpdater {
    public void updateProposition(final PropositionHolder holder, final String action) {
        holder.setProposition(holder.getProposition() + action);
    }
}

我将把 PropositionHolder 和 PropositionPanelUpdater 的默认值留给你想象;)

现在,这是你的动作监听器:

public class PropositionUpdaterActionListener implements ActionListener {
    private PropositionHolder holder;

    private PropositionUpdater updater;

    private PropositionPanelUpdater panelUpdater;

    public PropositionUpdaterActionListener(final PropositionHolder holder, final PropositionUpdater updater, final PropositionPanelUpdater panelUpdater) {
        super();
        this.holder = holder;
        this.updater = updater;
        this.panelUpdater = panelUpdater;
    }

    public void actionPerformed(final ActionEvent evt) {
        //Not sure how you *got* the action, but whatever...
        updater.updateProposition(holder, action);
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                panelUpdater.updatePropositionPanel();
            }
        });
    }
}
于 2010-03-25T13:13:40.857 回答
0

你没有说你在谈论多少个按钮。

如果它是像棋盘或更少的小数字,@juskt 的方法是一个很好的方法。

但是,如果您查看更大的内容,我会使用这种方法:

public class MyActionListener {
      public void actionPerformed(ActionEvent evt) {
          JComponent c = (JComponent)evt.getSoource();
          int prop = (Integer)c.getclientProperty("PROPOSITION");
          int act = (Integer)c.getclientProperty("ACTION");
          SomeClass obj = c.getclientProperty("UPDATE");
          prop += act;
          // If necessary, clientPut("PROPOSITION", prop);
          SwingUtilities.invokeLater(new    Runnable() {
              public void run() {
                  obj.updatePropositionPanel();
              }
          });
      }
}

这个动作监听器没有状态。因此,它的单个实例可用于所有按钮。对于像围棋板(19x19)这样的东西,这适用于 1 个对象而不是 361 个。

于 2010-03-25T13:51:21.323 回答