关于在JavaSwing中使用适配器和侦听器的一些疑问
我正在学习Java Swing和适配器来处理事件,但我对我正在学习的以下工作示例有一些疑问:关于在JavaSwing中使用适配器和侦听器的一些疑问,java,swing,listener,adapter,Java,Swing,Listener,Adapter,我正在学习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 JP
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只实现与窗口资源相关的方法,而不实现其他windows事件
这个推理正确吗
下面的示例显示了与使用classic listener概念的区别,在classic listener中,我必须实现处理与特定listener相关的所有事件的所有方法
在本例中,在my main()中,我向框架内容添加了一个自定义的ListenerDemo,我认为此侦听器通过以下行向当前对象添加了一个addMouseMotionListener:
addMouseMotionListener(this);
因此,我有一个监听器,它可以在我的框架内容中捕获与鼠标使用相关的所有事件
在这种情况下,因为我使用的是listener,所以我必须实现MouseMotionListenerlistener的两种方法:addMouseMotionListener和removeMouseMotionListener
对吗
我还有另一个疑问:在我看来,这种编码风格很可爱(但也许这只是我的印象,因为我不知道它),因为它在一个类中完成所有工作,我能以更好的方式将其分离吗
Tnx
Andrea您的
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
是很尴尬的。没有其他外部类需要知道您的演示可以捕获鼠标事件,因此它应该隐藏在其实现中。您的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
是很尴尬的。没有其他外部类需要知道您的演示可以捕获鼠标事件,因此它应该隐藏在其实现中。适配器类只是有用的存根,为实现接口的每个方法提供空实现。如果您不想实现所有方法,您可以使用它们——比如在您的示例中,您只对窗口关闭事件感兴趣
实现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”类中。适配器类只是有用的存根,为实现接口的每个方法提供空实现。如果您不想实现所有方法,您可以使用它们——比如在您的示例中,您只对窗口关闭事件感兴趣 实现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
关于你关于分离的问题:你应该/可以移动主要方法