关于在Java Swing中使用适配器和监听器的一些疑问

时间:2013-09-24 13:56:02

标签: java swing listener adapter

我正在研究Java Swing和 Adapters 来处理事件,但我对我正在研究的以下工作示例有一些疑问:

import java.awt.*;
import java.awt.event.*;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class ListenerDemo extends JPanel implements MouseMotionListener{

    // Label che visualizzano la posizione X ed Y del cursore:
    JLabel labelX;
    JLabel labelY;

    public ListenerDemo() {

        /* Add a MouseMotionListener to this object to catch when the user uses the mouse: */
        addMouseMotionListener(this);

        Font f = new Font(Font.SANS_SERIF, Font.PLAIN, 50);

        TitledBorder borderX = new TitledBorder("Mouse X");
        TitledBorder borderY = new TitledBorder("Mouse Y");

        borderX.setTitleJustification(TitledBorder.CENTER);
        borderY.setTitleJustification(TitledBorder.CENTER);

        labelX = new JLabel("0");
        labelX.setBorder(borderX);
        labelY = new JLabel("0");
        labelY.setBorder(borderY);

        labelX.setFont(f);
        labelY.setFont(f);
        super.add(labelX);
        super.add(labelY);

    }

    // NOT IMPLEMENTED:
    public void mouseDragged(MouseEvent e) {}

    // IMPLEMENTED:
    public void mouseMoved(MouseEvent e) {
         labelX.setText("X : "+e.getX());
         labelY.setText("Y : "+e.getY());
    }


    public static void main(String [] argv) {

        // WindowsAdapter che implementa solo il metodo WindowClosing()
        WindowAdapter adpt = new WindowAdapter() {
            /*
             * Alla chiusura della finestra ripassa il focus al frame principale.
             * @param A low-level event that indicates that a window has changed its status
             */
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        };

        JFrame frame = new JFrame("ListenerDemo");  // Frame esterno

        // Add at the frame ONLY the anonymous adapter WindowAdapter class:
        frame.addWindowListener(adpt);

        // Add to the ContentPane inside the frame the ListenerDemo listener:
        frame.getContentPane().add(new ListenerDemo(), null);

        // Display the window:
        frame.pack();
        frame.setVisible(true);
        frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    }
}

我很难理解这个程序的逻辑:

第一个疑问是为什么** ListenerDemo 类扩展JPanel并实现 MouseMotionListener

我认为该计划的逻辑如下:

main()方法中,我创建了一个新的 WindowAdapter 对象,该对象是 WindowAdapter 的一个实例,它允许我只实现一些处理与我的 WindowEvent 事件相关的事件的方法。因此,使用此适配器,我可以避免实现一些我不感兴趣的侦听器方法。在这种情况下,WindowAdapter只实现与窗口关闭相关的方法,而不实现其他窗口事件。

这种推理是否正确?

以下示例显示了使用经典侦听器的概念的不同之处,我必须实现处理与特定侦听器相关的所有事件的所有方法。

在这个示例中,在我的main()中,我将自定义 ListenerDemo 添加到框架的内容中,我认为此侦听器将 addMouseMotionListener 添加到当前这条线的对象:

addMouseMotionListener(this);

所以我有一个监听器,可以捕获与在我的框架内容中使用鼠标相关的所有事件。

在这种情况下,因为我正在使用监听器,所以我必须实现 MouseMotionListener 监听器的两种方法: addMouseMotionListener removeMouseMotionListener < / p>

这是对的吗?

我还有另一个疑问:在我看来,这种编码风格很糟糕(但也许只是我的印象,因为我不知道),因为它只在一个类中完成,我可以将它分开更好的方法?

TNX

安德烈

2 个答案:

答案 0 :(得分:3)

您的ListenerDemo是一个图形用户界面,这就是它扩展JPanel的原因:它继承了默认面板的所有图形属性。

在我看来,ListenerDemo也实施MouseMotionListener是不好的做法。这是对适配器模式的误用。那个模式是什么?

简而言之:在ListenerDemo中你有一些代码:

labelX.setText("X : "+e.getX());
labelY.setText("Y : "+e.getY());

您希望连接到面板事件:移动鼠标时。

典型的适配器模式使用匿名内部类:

public ListenerDemo() {

    addMouseMotionListener(new MouseMotionListener() {
        // NOT IMPLEMENTED:
        public void mouseDragged(MouseEvent e) {}

        // IMPLEMENTED:
        public void mouseMoved(MouseEvent e) {
            labelX.setText("X : "+e.getX());
            labelY.setText("Y : "+e.getY());
        }
    });

    // remaining code
}

效果是一样的,但在我看来,ListenerDemo实施MouseMotionListener是很尴尬的。没有其他外部类需要知道您的演示可以捕获鼠标事件,所以它应该隐藏在它的实现中。

答案 1 :(得分:3)

*Adapter类只是有用的存根,为实现接口的每个方法提供空实现。如果你不想实现所有方法,你可以使用它们 - 比如在你只关注窗口关闭事件的例子中。

实现UI的类也实现了事件处理程序接口,这是一种非常常见的做法。这主要是因为它很方便,但事实上它是糟糕的风格!您的ListenerDemo仅在内部需要侦听器,因此将其添加到类的公共API不是一个好主意。 (你不希望你班级的用户在MouseMotionListener的某个地方使用它,你呢?)

因此,拥有一个实现MouseMotionListener或派生自MouseAdapter的匿名内部类更好:

private final MouseMotionListener mouseListener = new MouseAdapter() {
    public void mouseMoved(MouseEvent e) {
        labelX.setText("X : "+e.getX());
        labelY.setText("Y : "+e.getY());
    }
}

现在,在构造函数中,您可以注册mouseListener而不是this

关于你关于分离的问题:你应该/可以将主要方法移到单独的“主”类中。