2009-05-21 46 views
5

我最近在做一个编程任务,要求我们在代码中实现一个由UML图指定的程序。在某一点上,图表指定我必须创建一个匿名JButton,它显示一个计数(从一开始),并在每次点击时递减。 JButton和它的ActionListener都必须是匿名的。实现ActionListener的Java匿名类?

我想出了以下解决方案:

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(),但是有没有另一种更优雅的方式来达到相同的结果?

+0

看一下你现在@Tim – Insane 2016-07-09 07:59:43

回答

11

我通常是这样的:

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

AbstractAction实现的ActionListener所以这应该满足的任务。

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

+0

这实际上并没有让你更改动作侦听器中的按钮文本...这是一个相当尴尬的要求,我想不出一种方法来改善你的Alrea dy有。 – Cogsy 2009-05-21 04:43:37

+0

那么匿名JButton中的计数器的公开声明以及ActionListener中对它的非限定访问是否可以? – Tim 2009-05-21 04:46:43

+0

是的,这是你能够在这些领域获得“处理”的唯一方法。请记住,内部类中的字段将隐藏在外部作用域中声明的相同名称的字段。希望你的编译器/ IDE会明确地警告你。 – Cogsy 2009-05-21 04:58:08

1

我不会在现实世界的程序中这样做,但考虑到您的任务中的要求,您几乎可以做得更好。

1

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

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

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

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

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

我不会在你的作业,虽然利用这一点,我已经看到了学生真正从规范和偏离得到标记下来,但至少你可以将其作为进一步调查的可能途径。

我认为你目前所拥有的绝对没问题。

2

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

很少有必要扩展JComponent类,尽管很多不好的软件和教程都这样做。最近获得成功的成语/攻击是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样板文件以确保Swing组件仅用于AWT EDT。

4

这是相当丑陋,但你可以做到以下几点使用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的两个地方访问它。

0

这是被迫的功课只做;-)不好的事情不好的实践任务之一:

  • ActionListener的,而不是行动的用法这是坏本身
  • 作为结果,确定范围的问题冒泡
    • 计数器的范围比必需
    • 需要更宽的actionPerformed内部访问按钮(通过型铸造或访问周围物体的API)
  • 不可读(又名:不可维护的)代码

但话..我们无法抗拒,我们可以;-)这里的使用正在清理行动的一个版本(或因此我认为),作为对前两个问题,无法读取所有其他的例子(我被骗了,当然,:首次实现了这种匿名类,然后让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); 
     }} 
    );