实现ActionListener的Java匿名类?

我最近做了一个编程任务,要求我们在代码中实现一个由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%5D [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); }} );