2

我曾尝试在 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);
    }

}

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

4

2 回答 2

5

它工作......是的。

话虽如此。我可以给你数百个糟糕的编码实践的例子,这就是其中之一。

  • 几乎从不需要扩展JxxxSwing 中的类(也许自定义绘画除外)。在您的示例中,您可以使用 aJFrame而不是扩展它
  • 拥有一个实现ActionListener接口的类向您的 API/代码的用户建议它可以用作ActionListener. 但是,您的课程并非设计为ActionListener. 它是一个事实是一个可以更好地隐藏的实现细节。所以使用ActionListener(anonymous class, inner class, ...) 而不是直接实现它(或者甚至更好,使用 an Action

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

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

于 2012-11-24T16:59:54.787 回答
4

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

这样做的副作用是:

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

  • 需要更多的检查来确定哪个组件正在触发侦听器(因为我看到许多其他组件的重用侦听器使用 if 检查哪个触发了侦听器)。

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

正确的解决方案 IMO:

使用匿名内部类监听器:

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

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

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

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

  • 正如我自己的编码偏好,不要使用EventQueue,而是SwingUtilities.invokeXXX@Robin 说谁说的文档:从 1.3 开始,这种方法只是一个掩护java.awt.EventQueue.invokeLater()
于 2012-11-24T17:00:08.630 回答