繁体   English   中英

实现ActionListener的Java匿名类?

[英]Java anonymous class that implements ActionListener?

我最近做了一个编程任务,要求我们在代码中实现一个由UML图指定的程序。 有一次,该图指定我必须创建一个显示计数(从1开始)的匿名JButton,并在每次单击时递减。 JButton及其ActionListener都必须是匿名的。

我提出了以下解决方案:

public static void main(String[] args) {
  JFrame f = new JFrame("frame");
  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  f.setSize(400, 400);

  f.getContentPane().add(new JButton() {

    public int counter;

    {
      this.counter = 1;
      this.setBackground(Color.ORANGE);
      this.setText(this.counter + "");

      this.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
          counter --;
          setText(counter + "");
        }
      });

    }
  });

  f.setVisible(true);

}

这会添加一个匿名的JButton,然后添加另一个(内部)匿名ActionListener来处理事件并根据需要更新按钮的文本。 有更好的解决方案吗? 我很确定我不能声明一个匿名JButton implements ActionListener () ,但还有另一种更优雅的方法来实现相同的结果吗?

我通常会这样:

JPanel panel = new JPanel();
panel.add(new JButton(new AbstractAction("name of button") {
    public void actionPerformed(ActionEvent e) {
        //do stuff here
    }
}));

AbstractAction实现了ActionListener,因此它应该满足任务。

将这么多行代码压缩在一起可能是不好的做法,但如果你习惯于阅读它,那么它可以非常优雅。

它非常难看,但您可以使用ActionListener方法和匿名类来执行以下操作:

  f.getContentPane().add(new JButton(new AbstractAction("name of button") {
      private int counter = 0;

      public void actionPerformed(ActionEvent e) {
          ((JButton) e.getSource()).setText(Integer.toString(counter--));
      }
  }) {
      {
          setText("1");
      }
  });

为了更容易访问计数器,您可以将其移出到类的顶层,并从调用setText的两个位置访问它。

实现多种类型通常是个坏主意。

虽然许多不好的软件和教程都是这样做的,但很少需要扩展JComponent类。 最近获得支持的成语/ hack是Double Brace - 一个类只是子类,以便为它提供一个实例初始化器,其作用类似于来自其他语言的with语句。

在这种情况下,相关代码可以写成:

JButton button = new JButton();
button.addActionListener(new ActionListener() {
    int counter = 1;
    {
        updateText();
    }
    public void actionPerformed(ActionEvent arg0) {
        --counter;
        updateText();
    }
    private void updateText()
        setText(Integer.toString(counter));
    }
});
f.getContentPane(button);

如果它变得更复杂,那么你可能想要创建一个外部类(不实现ActionListener或扩展JButton )来处理数据。

另请注意,您应该使用EventQueue.invokeLater样板来确保仅在AWT EDT上使用Swing组件。

在现实世界的计划中,我不会做那样的事情,但考虑到你的任务要求,你几乎无法做得更好。

那么有一种更优雅的方式来做到这一点。

不幸的是,它不是Core Java / Swing方法。

您可以使用Groovy中的SwingBuilder来实现相同的结果,使用稍微简洁的语法,例如伪代码:

button(text: '' + counter,
         actionPerformed: {counter--; text = '' + counter + ''},
         constraints:BL.SOUTH)

[ http://groovy.codehaus.org/Swing+Builder] [1 ]

我不会在你的作业中使用这个,但是我看到学生们真的偏离了常规而得到了标记,但至少你可以把它作为进一步调查的可能途径。

我觉得你现在拥有的东西绝对没问题。

这是仅在家庭作业中被迫做的不良练习任务之一;-)坏事:

  • 使用ActionListener而不是Action本身就不好用
  • 结果,范围界定问题起了泡沫
    • 反对范围超出必要范围
    • 需要访问actionPerformed中的按钮(通过类型转换或访问周围对象的api)
  • 不可读(又名:不可维护)的代码

但是,那么..我们无法抗拒,我们可以;-)这是一个使用Action的版本,对于前两个问题是干净的(或者我认为),与其他所有例子一样难以理解(当然我作弊:首先实施匿名类,然后让IDE执行内联

    f.add(new JButton(new AbstractAction() {

        int counter = 1;
        { // constructor block of action
            updateName();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            counter--;
            updateName();
        }

        private void updateName() {
            putValue(Action.NAME, "" + counter);
        }

    })  { // subclass button 
          {  // constructor block button
            setBackground(Color.PINK);
        }}
    );

暂无
暂无

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

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