简体   繁体   English

可以添加一个ActionListener吗?我可以为actionPerformed添加参数吗?

[英]Can addition of an ActionListener be short? Can I add arguments to the actionPerformed?

I have a big table containing a button in each cell. 我有一个大表,每个单元格中都有一个按钮。 These buttons are very similar and do almost the same. 这些按钮非常相似,几乎相同。 If I add an action listener to every button in this way: 如果我以这种方式向每个按钮添加一个动作侦听器:

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

Actually, every action listener differ from all others by the value of the action . 其实,每一个动作监听器与所有其他由的值不同action proposition and updatePropositionPanel are a field and a method of the class. propositionupdatePropositionPanel是该类的字段和方法。

  1. First i thought that I can make it shorter if I do not use inner classes. 首先,如果我不使用内部类,我认为我可以缩短它。 So, I decided to program a new ActionListener class. 所以,我决定编写一个新的ActionListener类。 But than I realized that in this case "proposition" will not be visible to the instances of this class. 但是我意识到在这种情况下,“命题”对于这个类的实例是不可见的。

  2. Then I decided to add the actionPerformed method to the current class and do that: addActionListener(this) . 然后我决定将actionPerformed方法添加到当前类并执行: addActionListener(this) But than I realized that I do not know how give arguments to the actionPerformed method. 但是我意识到我不知道如何为actionPerformed方法提供参数。

So, how does it work. 那么它是怎样工作的。 Can I add an action listener in a short and elegent way? 我可以以简短的方式添加动作侦听器吗?

ADDED: 添加:

I liked the idea to program an inner class with a constructor which can take some arguments and actioPerformed method, which can use arguments given in the constructor. 我喜欢用构造函数编写内部类的想法,它可以使用一些参数和actioPerformed方法,它可以使用构造函数中给出的参数。 I started to do so and then realized that it creates a conflicts with other inner anonymous classes (used like in the above given code). 我开始这样做,然后意识到它与其他内部匿名类创建冲突(像上面给出的代码一样使用)。 So, I think I will create another class (not inner one). 所以,我想我会创建另一个类(不是内部类)。

You can create your own class and pass the data into the constructor. 您可以创建自己的类并将数据传递给构造函数。 For example 例如

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

Then you can add it as normal, passing whatever arguments you like to the constructor: 然后你可以正常添加它,将你喜欢的任何参数传递给构造函数:

tmp.addActionListener( new MyActionListener(proposition, this) );

EDIT : I have altered the class to show construction with MyOuterClass. 编辑 :我已经改变了类来显示MyOuterClass的构造。

Here is some code sketched out. 这里有一些代码勾勒出来。 Hopefully this gets at your 1, which is how I would implement it. 希望这会得到你的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;
        }
    }
}

EDIT : To create another class as you asked for in your edit, do as above but create a non-private other class in another .java file and code away. 编辑 :要在编辑中按要求创建另一个类,请执行上述操作,但在另一个.java文件中创建非私有其他类并编写代码。

As the only different is in the value of action you can place the code within a method. 唯一不同的是action的价值,您可以将代码放在方法中。 (Also the @Override is unnecessary, and += is useful here.) (另外@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();
                }
           });
        }
    });
}

The invokeLater is probably pointless as you will be on the AWT Event Dispatch Thread (EDT) anyway. invokeLater可能毫无意义,因为无论如何你将参加AWT事件调度线程(EDT)。

If you are adding lots of general purpose actions, then you could simplify it by using an interface that doesn't have a pointless event object associated with it. 如果要添加许多通用操作,则可以使用没有与之关联的无意义事件对象的接口来简化它。

If you wanted to be hackish you could add the listener in a subclass constructor. 如果你想成为hackish,你可以在子类构造函数中添加监听器。

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

Hopefully, JDK7 will make the Java syntax for this sort of thing less verbose. 希望JDK7能够使这种事情的Java语法不那么冗长。 Java will, however, always be somewhat verbose. 但是,Java总是有点冗长。

Option 1 works if you make proposition mutable (eg StringBuilder instead of String ). 如果你使proposition可变,则选项1有效(例如StringBuilder而不是String )。 Option 2 works if you declare them final . 如果您将其声明为final则选项2有效。 This way they're accessible/visible in the inner class. 这样它们在内部类中是可访问/可见的。

You could create a separate MyActionListener class and pass the two values proposition and action with the constructor. 您可以创建一个单独的MyActionListener类,并使用构造函数传递两个值命题和操作。 It declutters the source code. 它整理了源代码。

You could create your own listener class that implements ActionListener. 您可以创建自己的侦听器类来实现ActionListener。 This class could contain member variables corresponding to the parameters you're talking about; 该类可以包含与您正在讨论的参数对应的成员变量; you'd set them using the constructor. 你可以使用构造函数设置它们。

The call to add the listener would then look something like this: 添加侦听器的调用将看起来像这样:

tmp.addActionListener(new MyActionListenerSubClass(proposition, action));

I'll assume that your proposition and action variables are Strings for the sake of this example. 为了这个例子,我假设你的命题和动作变量是字符串。 Define an interface PropositionUpdater, an interface PropositionPanelUpdater, and a collaborator proposition holder: 定义一个接口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();
}

The default implementation of a proposition updater is simply this: 命题更新程序的默认实现就是:

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

I'll leave the default of a PropositionHolder and PropositionPanelUpdater to your imagination ;) 我将保留一个PropositionHolder和PropositionPanelUpdater的默认值给你的想象力;)

Now, here's your action listener: 现在,这是你的动作监听器:

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

You didn't say how many buttons you are talking about. 你没有说你正在谈论多少个按钮。

If it's a small number like a chess board or less, @juskt's approach is a good one. 如果它是一个像棋盘或更少的棋盘,@ juskt的方法是一个很好的方法。

However, if you looking at something larger, I would use this approach: 但是,如果你看一些更大的东西,我会用这种方法:

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

This action listener holds no state. 此动作侦听器不保持任何状态。 As a result, a single instance of it can be used for all of the buttons. 因此,它的单个实例可用于所有按钮。 For something like a Go board (19x19), this works out to 1 object instead of 361. 对于像Go板(19x19)这样的东西,这可以用于1个对象而不是361个。

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

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