组件本身可以用作监听器吗?

时间:2012-11-24 16:38:02

标签: java swing user-interface jframe actionlistener

我尝试在Java中使用此代码,我使用JFrame作为自己的ActionListener。现在,它在理论上是可行的,因为在Java中,类可以实现许多接口扩展另一个类。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;

/*
 * This is an example of the strangeness of the syntax of Java. In this example, I am using the JFrame itself as the listener for its component, namely a JButton which, on clicking, ends the program. 
 * Warning : This is just an example, and I would never recommend this syntax, for I do not know the full consequences yet.
 */

@SuppressWarnings("serial") public class ListenerTest extends JFrame implements ActionListener{

    private final JPanel contentPane;
    private final JLabel message;
    private final JButton button;

    /**
     * Launch the application.
     */
    public static void main(String[] args){
        EventQueue.invokeLater(new Runnable(){
            @Override public void run(){
                try{
                    ListenerTest frame = new ListenerTest();
                    frame.setVisible(true);
                } catch(Exception e){
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the frame.
     */
    public ListenerTest(){
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 200, 150);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        contentPane.setLayout(new BorderLayout(0, 0));

        message = new JLabel("Hello World");
        message.setFont(new Font("Times New Roman", Font.PLAIN, 16));
        message.setHorizontalAlignment(SwingConstants.CENTER);
        contentPane.add(message, BorderLayout.CENTER);

        button = new JButton("Click Me!");
        button.addActionListener(this);
        contentPane.add(button, BorderLayout.SOUTH);
    }

    @Override public void actionPerformed(ActionEvent arg0){
        JOptionPane.showMessageDialog(null, "Well, I listened for myself!");
        System.exit(0);
    }

}

我的问题是:使用组件作为自己的监听器有什么问题吗?

2 个答案:

答案 0 :(得分:5)

是否有效......是的。

话虽如此。我可以举几百个不良编码实践的例子,这就是其中之一。

  • 几乎从来没有必要在Swing中扩展Jxxx类(除了自定义绘画之外)。在您的示例中,您可以使用JFrame而不是扩展
  • 有一个实现ActionListener接口的类建议您的API /代码的用户可以将其用作ActionListener。但是,您的课程并非设计为ActionListener。它是一个的事实是一个可以更好地隐藏的实现细节。所以使用ActionListener(匿名类,内部类,......)而不是直接实现它(甚至更好,使用Action

不,直接实现ActionListener接口与无关我看到GUI需要很长时间才能加载

作为旁注。最好使用JFrame#pack()然后调用setBounds

答案 1 :(得分:4)

如果仅用于单个按钮,为什么要在类上实现ActionListener

这样的副作用是:

  • 增加了其他类和组件可以访问此侦听器的事实

  • 需要进行更多检查以确定哪个组件正在触发侦听器(因为我看到许多重用侦听器用于其他组件,如果检查触发了侦听器)。

  • 在类上实现Listener并不是很好的做法,除非将该类用作监听器。

正确的解决方案IMO:

Use anonymous inner class listeners:

ActionListener al=new ActionListener() {
    @Override
     public void ActionPerformed(ActionEvent ae) {
     }
};

现在您可以通过addActionListener将其添加到您的单个按钮。

我得出上述不希望在类上实现侦听器的结论的原因是在Swing中你不应该不必要地扩展JFrame类。

备注(与特定问题无关):

  • 由于我自己的编码偏好不使用EventQueue而不是SwingUtilities.invokeXXX,因为@Robin说谁说明了文档:从1.3开始,此方法只是java.awt.EventQueue.invokeLater()的封面