10장 - 자바의 이벤트 처리
event 기반 프로그래밍 - event listener
↔ batch programming (개발자가 흐름 결정 방식)
처리 순서 : event 발생 > event 객체 생성 > event listener 찾기 > 호출 > 실행
event source - GUI component // ex) JButton component
event 객체 - event 정보(종류, 소스, 화면 좌표, 마우스 버튼 종류, 눌린 키)
event listener - event 처리 코드 (component에 등록 되어야 작동 가능)
event 분배 thread - 무한 루프 실행 thread
// JVM으로부터 이벤트 발생 통지 받음 > 이벤트 소스, 종류 결정 > 객체 생성 > 리스너 호출
event 객체
현재 발생한 event 관련 정보 담은 객체 (event listener에 전달됨)
java.util.EventObject 에 상속 받음 (최상위 클래스)

import java.awt.event.*;
import javax.swing.event.*;
// event 객체 정보
ActionEvent - action 문자열
MouseEvent - mouse 위치 정보, 버튼, 함께 눌린 키 정보 등
ItemEvent - item check 상태
// getSource - 이벤트 소스 받기 (Object 타입)
JButton b = (JButton)event.getSource();
// ex
event 객체 - MouseEvent
event source - Component // 무슨 컴포넌트를 누른거냐
event 발생 경우 - 7개
event listener - interface의 모든 추상 method 다 구현 필요 !!
JDK에서 interface 제공 (상속, 추상 메소드 모두 구현 필요)
// mouse click 시 event listener 순서
mousePressed > mouseReleased > mouseClicked
// ActionListener
// 추상 method 모두 구현 필요
interface ActionListener {
public void actionPerformed(ActionEvent e);
}
// MouseListener
interface MouseListener {
public void mousePressed(MouseEvent e);
public void mouseReleased(MouseEvent e);
public void mouseClicked(MouseEvent e);
public void mouseEntered(MouseEvent e);
public void mouseExited(MouseEvent e);
}
event listener 작성 과정
이벤트, 이벤트 리스너 선택 (이벤트 타입, 이벤트 리스너, 이벤트 객체)
listener class 작성 (추상 메소드 모두 구현)
listener 등록 (swing component에 event listener 등록)
// 1. 선택 (이벤트 : Action 이벤트, 리스너 : ActionListener, 객체, ActionEvent)
// 2. listener class 작성
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) { // ActionListener의 method 구현
JButoon b = (JButton)e.getSource(); // 이벤트 소스
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
}
}
// 3. listener 등록
MyActionListener listener = new MyActionListener(); // 객체 생성
btn.addActionListener(listener); // button component에 등록
// 등록 시 유의사항 - 모든 component가 해당 listener를 갖고 있는건 아님
JButton b = new JButton("test");
b.addItemListener(listener); // error - JButton에는 addItemListener 없음
JScrollBar s = new JScrollBar();
s.addActionListener(listener); // error - JScrollBar에 addActionListener 없음
event listener 작성 방법 - (독립 class, 내부 class, 익명 class)
// 독립 class로 작성 - 리스너를 완전한 class로
// 리스너를 "여러 곳"에서 사용할 때 적합
// 다른 class이므로 IndepClassListener의 멤버 접근 불가
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class IndepClassListener extends JFrame {
public IndepClassListener() {
setTitle("Action 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
JButton btn = new JButton("Action");
btn.addActionListener(new MyActionListener()); // 리스너 등록
c.add(btn);
setSize(350, 150);
setVisible(true);
}
public static void main(String[] args) {
new IndepClassListener();
}
}
// 독립 class로
class MyActionListener implements ActionListener { // interface ActionListener 상속
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource(); // 이벤트 소스 받기 (JButton)
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
}
}
// 내부 class로 - class안에 멤버처럼
// 리스너를 "특정 class에서만" 사용할 때 적합
// 상속 부모 class, JFrame 멤버 접근 가능
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class InnerClassListener extend JFrame {
public InnerClassListener() {
setTitle("Action 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
JButton btn = new JButton("Action");
btn.addActionListener(new MyActionListener()); // 리스너 등록
c.add(btn);
setSize(350, 150);
setVisible(true);
}
// 내부 class로
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource(); // 이벤트 소스 받기 (JButton)
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
InnerClassListener.this.setTitle(b.getText());
}
}
public static void main(String[] args) {
new InnerClassListener();
}
}
// 익명 class - class 이름 없이 간단히 리스너 작성
// class 필요없이 호출 부분에 연달아 작성 - 바로 객체 생성
// class 정의 + instance 생성 한 번에
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class AnonymousClassListener extend JFrame {
public AnonymousClassListener() {
setTitle("Action 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
JButton btn = new JButton("Action");
// 익명 class로
btn.addActionListener(new MyActionListener() {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
if (b.getText().equals("Action")
b.setText("액션");
else
b.setText("Action");
setTitle(b.getText);
}
}); // 리스너 등록
c.add(btn);
setSize(350, 150);
setVisible(true);
}
public static void main(String[] args) {
new InnerClassListener();
}
}
// 예제 10-4
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MouseListenerEx extends JFrame {
private JLabel la = new JLabel("Hello");
public MouseListenerEx() {
setTitle("Mouse이벤트 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.addMouseListener(new MyMouseListener());
c.setLayout(null);
la.setSize(50, 20);
la.setLocation(30, 30);
c.add(la);
setSize(250, 250);
setVisible(true);
}
class MyMouseListener implements MouseListener {
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
la.setLocation(x - 13, y - 10);
}
public void mouseReleased(MouseEvent e) { }
public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
}
public static void main(String[] args) {
new MouseListenerEx();
}
}
Adapter class - event listener의 모든 추상 method 구현해야하는 불편 해결
listener의 모든 method가 단순 return 하도록 구현한 class

추상 method가 하나인 listener는 adapter class 없음 (ActionListener, ItemListener)
// Adapter class
class MouseAdapter implements MouseListener, MouseMotionListener, MouseWheelListener {
public void mousePressed(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { }
public void mouseClicked(MouseEvent e) { }
public void mouseEntered(MouseEvent e) { }
public void mouseExited(MouseEvent e) { }
public void mouseDragged(MouseEvent e) { }
public void mouseMoved(MouseEvent e) { }
public void mouseWheelMoved(MouseEvent e) { }
}
// MouseAdapter로 예제 10-4 수정
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MouseAdapterEx extends JFrmae {
private JLabel la = new JLabel("Hello");
public MouseAdapterEx() {
setTitle("Mouse이벤트 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.addMouseListener(new MyMouseAdapter());
c.setLayout(null);
la.setSize(50, 20);
la.setLocation(30, 30);
c.add(la);
setSize(250, 250);
setVisible(true);
}
class MyMouseAdapter extends MouseAdapter { // class라 extends
public void mousePressed(MouseEvent e) { // 필요한 method만 구현
int x = e.getX();
int y = e.getY();
la.setLocation(x, y);
}
}
public static void main(String[] args) {
new MouseAdapterEx();
}
Key 이벤트, KeyListener
key event - 사용자 키 입력 시 발생하는 event (모든 component가 수신 가능)
foucs - key 입력 독점권 (focus를 가진 component에만 key event 전달됨)
// focus 설정 방법 - 아래 2개 line 필요
component.setFocusable(true); // focus 가능하도록 지정
component.requestFocus(); // foucs 강제 지정
// focus 주는 타이밍 1 - setVisible 직후 (focus 임의 움직임 이슈)
setVisible(true);
component.setFocusable(true);
component.requestFocus();
// focus 주는 타이밍 2 - mouse로 component 클릭할 때
component.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
Component c = (Component)e.getSource(); // mouse로 클릭한 컴포넌트
c.setFocusable(true);
c.requestFocus(); // 마우스로 클릭한 컴포넌트에게 focus
}
});
// KeyListener method
void keyPressed(KeyEvent e) { ... } // key 눌린 순간
void keyReleased(KeyEvent e) { ... } // key 뗀 순간
void keyTyped(KeyEvent e) { ... } // key 뗀 순간 (Unicode에서 추가 발생)
// Unicode = 알파벳, 숫자, 문자 기호 등 (F1, home, del 등은 unicode X)
// 실행 순서 (ex. 'f' 누름)
keyPressed() -> keyTyped() -> keyReleased() 순
// 'home'키 누름
keyPressed() -> keyReleased() 순
가상 키 (virtual key) - 어떤 key인지 비교 판단 가능
KeyEvent class에 VK_로 시작하는 static 상수로 선언

// 입력된 key 판별 방법
// key의 unicode return (문자 키에만 작동) - unicode X = CHAR_UNDEFINED return
public void keyPressed(KeyEvent e) {
if (e.getKeyChar() == 'q') // 'q' 누르면 종료
System.exit(0);
}
// key code 값 return
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_F5) // 'F5' 누르면 종료 (가상 키 값 비교)
System.exit(0);
}
// key 이름 문자열 return ("SHIFT", "F1") - static method
static String KeyEvent.getKeyText(int keyCode);
MouseEvent, MouseListener, MouseMotionListener, MouseWheelListener
// mouse 눌린 위치에서 떼어지는 경우 호출 순서
mousePressed() -> mouseReleased() -> mouseClicked()
// Released() : 마우스 떼면 무조건 호출
// Clicked() : 누른 위치 = 뗀 위치 (이동 X) 에만 호출
// mouse 드래그 시 호출 순서
mousePressed() -> mouseDragged() -> mouseDragged -> ... -> mouseReleased()
// MouseListener - method 5개
void mousePressed(MouseEvent e) {}
void mouseReleased(MouseEvent e) {}
void mouseClicked(MouseEvent e) {}
void mouseEntered(MouseEvent e) {}
void mouseExited(MouseEvent e) {}
// MouseMotionListener - method 2개
void mouseDragged(MouseEvent e) {}
void mouseMoved(MouseEvent e) {}
// MouseWheelListener - method 1개
void mouseWheelMoved(MouseWheelEvent e) {}
// MouseEvent 객체 - MouseEvent, MouseMotionEvent의 정보
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
}
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) { ... }
}
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1)
System.out.println("Left Button Pressed");
}
// MouseWheelEvent 객체 - MouseWheelEvent의 정보
public void mouseWheelMoved(MouseWheelEvent e) {
... // wheel 움직임 따라 event 처리
}