이 테크팁의 영문 원본은 http://java.sun.com/mailers/techtips/co ··· html%231
에서 볼수 있습니다.
JavaBeans 구성 요소 모델(즉 Swing 구성 요소 세트)은 등록 정보(properties)와 이벤트를 기반으로 한다. 등록 정보에는 그 값을 사용하도록 setter 및 getter 메소드가 있다. 이벤트에서는 수신기(listener)를 사용하고 인터페이스를 구현해야 그 이벤트 발생에 대한 알림을 수신할 수 있다. 등록 정보 작업은 간단하지만, 수신기 객체는 그 작동 방식, 주로 GUI(graphical user interface) 영역에 관해 이해하려면 약간의 추가적인 학습이 필요하다. 이번 팁에서는 수신기 인터페이스와 어댑터 구현을 모두 제공하는 AWT 및 Swing 이벤트 관련 클래스에 대해 소개한다.
다음 클래스는 수신기와 어댑터 쌍의 예제를 보여 준다.
package java.awt.event- ComputerListener/ComputerAdapter- ContainerListener/ContainerAdapter- FocusListener/FocusAdapter- HierarchyBoundsListener/HierarchyBoundsAdapter- KeyListener/KeyAdapter- MouseListener/MouseAdapter- MouseMotionListener/MouseMotionAdapter- WindowListener/WindowAdapterpackage java.awt.dnd- DragSourceListener/DragSourceAdapter- DragTargetListener/DragTargetAdapterpackage javax.swing.event- InternalFrameListener/InternalFrameAdapter- MouseInputListener/MouseInputAdapter이 클래스 쌍은 두 가지 방법으로 동일한 목적을 수행한다. 먼저 어댑터 클래스를 제공하지 않는 간단한 예제를 소개한다. ActionListener 클래스는 단일 actionPerformed 메소드를 갖고 있다. 익명 내부 클래스를 사용할 때 주로 다음 방법으로 ActionListener 클래스를 사용한다.
ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { System.out.println("Event happened"); }};또한 상위 수준 클래스에서 ActionListener 인터페이스를 구현하는 방법으로 actionPerformed 메소드를 사용할 수도 있다.
public class MyClass extends JFrame implements ActionListener { ... public void actionPerformed(ActionEvent actionEvent) { System.out.println("Event happened"); }}ActionListener 인터페이스는 단일 메소드를 가지며, 이 인터페이스의 구현자가 그 단일 메소드의 구현을 제공해야 많은 기능을 수행할 수 있다.
다른 수신기 인터페이스는 이만큼 간단하지 않다. 예를 들어, MouseMotionListener 인터페이스는 두 개의 메소드, 즉 mouseDragged와 mouseMoved를 갖는다. 인터페이스를 구현할 때 그 인터페이스에서 정의하는 모든 메소드를 구현해야 한다.
MouseMotionListener listener = new MouseMotionListener() { public void mouseDragged(MouseEvent mouseEvent) { System.out.println("I'm dragging: " + mouseEvent); } public void mouseMoved(MouseEvent mouseEvent) { System.out.println("I'm moving: " + mouseEvent); }};응용 프로그램이 특정 수신기 인터페이스의 이벤트 중 일부를 추적할 필요가 없는 경우가 있다. 아마 코드에서는 수신기 인터페이스의 메소드 한 두 개에 응답하면 될 것이다. 예를 들어, 언제 마우스가 움직이는지 아니면 단지 마우스 버튼이 눌러진 상태에서 언제 마우스가 움직이는가를 정말 알아야 하는가? MouseMotionListener 메소드 중 하나만 구현하고 나머지를 생략할 수는 없다.
MouseMotionListener badListener = new MouseMotionListener() { public void mouseDragged(MouseEvent mouseEvent) { System.out.println("I'm dragging: " + mouseEvent); }};이 수신기 구현은 인터페이스가 완전히 구현되지 않았기 때문에 컴파일 시 오류가 발생한다. MouseMotionListener와 같은 인터페이스에서 이는 그리 큰 문제가 되지 않는다. 필요 없는 메소드에 대해서는 스텁(stub)만 제공하면 된다.
MouseMotionListener listener = new MouseMotionListener() { public void mouseDragged(MouseEvent mouseEvent) { System.out.println("I'm dragging: " + mouseEvent); } public void mouseMoved(MouseEvent mouseEvent) { // Do nothing }};모든 수신기 인터페이스가 이렇게 작은 것은 아니다. MouseMotionListener에는 단 2개의 메소드가 있지만 MouseListener 인터페이스에는 5개가 존재한다.
void mouseClicked(MouseEvent mouseEvent) void mouseEntered(MouseEvent mouseEvent) void mouseExited(MouseEvent mouseEvent) void mousePressed(MouseEvent mouseEvent) void mouseReleased(MouseEvent mouseEvent)MouseListener를 어떤 구성 요소에 추가하려면 인터페이스 구현에 5개의 메소드가 포함되어야 한다.
MouseListener mouseListener = new MouseListener() { public void mouseClicked(MouseEvent mouseEvent) { System.out.println("I'm clicked: " + mouseEvent); } public void mouseEntered(MouseEvent mouseEvent) { System.out.println("I'm entered: " + mouseEvent); } public void mouseExited(MouseEvent mouseEvent) { System.out.println("I'm exited: " + mouseEvent); } public void mousePressed(MouseEvent mouseEvent) { System.out.println("I'm pressed: " + mouseEvent); } public void mouseReleased(MouseEvent mouseEvent) { System.out.println("I'm released: " + mouseEvent); }};응용 프로그램에서 어떤 구성 요소에 대해 마우스가 눌러졌는지 또는 릴리스되었는지 여부만 알면 되는 경우, 나머지 세 메소드는 비어 있고 무시된다. 이 메소드는 불필요한 코드이다. 어댑터 클래스는 응용 프로그램에서 모든 인터페이스 메소드 중 극히 일부만 필요한 경우 작성해야 하는 코드의 양을 줄이는 데 도움이 된다. 각 어댑터 클래스는 연결된 인터페이스를 모두 구현한다. 그런 다음 연결된 메소드 중 하위 집합에 대해 수신기가 필요한 경우, 그 하위 집합만 제공하면 된다. 빈 스텁은 필요하지 않다. 다음은 앞서 설명한 필수 MouseListener에 대한 어댑터이다.
MouseListener mouseListener = new MouseAdapter() { public void mousePressed(MouseEvent mouseEvent) { System.out.println("I'm pressed: " + mouseEvent); } public void mouseReleased(MouseEvent mouseEvent) { System.out.println("I'm released: " + mouseEvent); }};이 코드는 여전히 MouseListener를 생성한다. 그러나 필요 없는 모든 인터페이스 메소드를 구현하지 않고 MouseAdapter의 도움을 받아 정말 필요한 MouseListener 메소드만 구현하면 된다.
모든 다중 메소드 수신기에게 어댑터가 있는 것은 아니다. 어떤 인터페이스에 대해 끊임 없이 스텁을 지정하고 있다면 직접 만들 수도 있다. 기본 제공된 클래스 중에서 이 팁의 맨 위에 표시된 수신기만 어댑터를 제공한다. 또한 어댑터는 실제로 인터페이스가 아니라 클래스이다. 사용자 정의 JButton 하위 클래스가 MouseListener도 구현하게 하려면 그 클래스가 MouseAdapter의 하위 클래스가 될 수는 없다. 단일 상속만 허용되기 때문이다. 예를 들어, 다음 코드에서는 컴파일 시 오류가 발생하는데, JButton과 MouseAdapter 모두의 하위 클래스가 되려고 했기 때문이다.
public class BadJButtonSubclass extends JButton, MouseAdapter { ... public void mousePressed(MouseEvent mouseEvent) { System.out.println("I'm pressed: " + mouseEvent); }}이 JButton 하위 클래스가 반드시 MouseListener가 되어야 한다면, 명시적으로 이를 표현하고 그 인터페이스의 모든 메소드를 구현해야 한다.
public class GoodJButtonSubclass extends JButton implements MouseListener { ... public void mouseClicked(MouseEvent mouseEvent) { // Do nothing } public void mouseEntered(MouseEvent mouseEvent) { // Do nothing } public void mouseExited(MouseEvent mouseEvent) { // Do nothing } public void mousePressed(MouseEvent mouseEvent) { System.out.println("I'm pressed: " + mouseEvent); } public void mouseReleased(MouseEvent mouseEvent) { // Do nothing } ... addMouseListener(this); ...}
물론 상위 수준 클래스가 직접 인터페이스를 구현하게 할 필요는 없다. 이는 수신기를 내부 또는 익명 클래스로 생성해야 하는 경우의 대표적인 예가 될 것이다.
사용자 인터페이스 생성에 IDE(integrated development environment)를 사용한다면 IDE가 인터페이스 프레임워크를 대신 생성해 주는 경우가 많다. 필요한 인터페이스 메소드 내부에 비즈니스 논리를 코딩해야 한다. IDE는 큰 규모의 인터페이스 구현을 간소화할 수 있다.
이 주제에 대한 자세한 내용은 The Java Tutorial 중 How to Write a Mouse Listener 부분을 참조한다.
어댑터는 마우스 수신으로 국한되지 않는다. 그러나 MouseAdapter가 대표적인 예가 되는데, MouseListener 인터페이스에 메소드가 많기 때문이다. WindowListener 인터페이스 역시 큰 인터페이스이며, WindowAdapter 클래스가 연결되어 있다.
"Java SE" 카테고리의 다른 글
- 리스너 리스트를 위한 WEAKHASHMAP 사용하기 (댓글 1개 / 트랙백 0개) 2006/03/08
- J2SE 5.0의 Java 2D API 기능 강화 (댓글 2개 / 트랙백 0개) 2006/05/12
- 3D 화면(scene)에 빛 효과 주기 (댓글 1개 / 트랙백 0개) 2004/07/30
- 다이얼로그 Modality (댓글 1개 / 트랙백 0개) 2006/06/09
- 쿠키 처리 (댓글 22개 / 트랙백 3개) 2007/07/23
- 사용자 데이터그램 프로토콜의 프로그래밍 (댓글 1개 / 트랙백 0개) 2004/06/30
- 락(LOCKS) (댓글 1개 / 트랙백 0개) 2005/09/22
- Java Web Start 퍼시스턴스 (댓글 3개 / 트랙백 0개) 2006/12/24
- AFFINETRANSFORM 이해하기 (댓글 3개 / 트랙백 0개) 2003/09/09
- 사용자 인터페이스에서 Action 사용하기 (댓글 5개 / 트랙백 2개) 2007/02/22
TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/424
-
수신기와 어댑터 (Listeners vs Adapters)
Tracked from ★ dingpong의 조그만 휴식 공간 ★ 삭제수신기와 어댑터 (Listeners vs Adapters)에 대한 내용입니다. 수신기는 gui 같은데서 이벤트 정보를 주고 받는데 쓰일 수 있는 것 같습니다. 제가 하고 있는 프로젝트에서도 순수 가상함수로 지정되어 리스너로 해서 설계가 되어 이벤트를 주고 받는 것이 많은데요. 자바에서도 그런 식의 프로그래밍을 할 수 있게 이렇게 되어
2007/09/19 23:26
댓글을 달아 주세요
좋은정보 감사합니다.
2007/09/04 17:58앞으로도 멋진 사이트로 남길 바래요
2007/09/06 10:16배우기에 어려울 수 있는 자바..배우고 알아갈수록 자바의 매력에 푹~ 빠진다.
2007/09/10 10:15배워두면 좋죠....
2007/09/10 13:57이런 정보까지....
2007/09/11 11:58공부하시는 분들에게 정말 좋다고 생각되는 정보입니다.
아 다소 어렵네요 ㅜㅜ
2007/09/13 10:38항상 요긴한 정보로 도움을 많이 받고 있습니다. 자바 신기술 따라잡기에 썬 개발자 네트워크만큼 좋은 곳도 없나봅니다. 언제나 좋은 자료 감사합니다.
2007/09/16 22:44공짜로 많은 정보들을 그냥 얻어갈려고 하니 미안해지네요.
2007/09/19 02:53좋은 정보 감사해요~
2007/09/19 03:21좋은자료 많이 많이 올려주세요..감사
2007/09/19 06:42저에게 많은 도움이 되어서 정말 좋은데 차근차근 알아가도록 할께요..정보 감사합니다^^
2007/09/19 19:19알았던 내용이지만 다시 복습하니 새롭네요.
2007/09/19 19:20직접적인 개발자가 아니라서 정확한 세부사항까지 이해하기는 어려웠지만 나름 좋은 지식공유가 된것 같아서 기쁘네요... 앞으로도 좋은 지식발견이 되었으면 좋겠습니다. 감사합니다...!
2007/09/19 21:08좋은 정보 공유해 주셔서 감사해요~
2007/09/19 22:35정보 감사드려요 ^^
2007/09/19 23:02담아갑니다. 수신기는 저도 프로젝트에서 많이 쓰고 있는 내용이네요. 필수적인 내용이라고 생각합니다^-^
2007/09/19 23:26