1

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

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监听器的两个方法:addMouseMotionListenerremoveMouseMotionListener

这是对的吗?

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

肿瘤坏死因子

安德烈亚

4

2 回答 2

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。没有其他外部类需要知道您的演示可以捕获鼠标事件,因此它应该隐藏在其实现中。

于 2013-09-24T14:14:56.710 回答
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.

关于您关于分离的问题:您应该/可以将 main 方法移出一个单独的“Main”类。

于 2013-09-24T14:15:19.990 回答