Event 처리
- Event는 외부에서 발생하는 사건
- 자바의 awt 나 swing의 이벤트 처리는 Listener 인터페이스나 Adapter 클래스가 처리합니다.
1.이벤트 처리 방법
처리하고자 하는 이벤트의 Listener 인터페이스를 implements 하거나 Adapter 클래스를 상속받은 클래스의 인스턴스를 생성
컴포넌트.add이벤트리스너(앞에서 생성한 인스턴스);
이러한 방식의 처리를 Delegate(위임) 를 처리 방식
- 이벤트가 발생한 객체가 이벤트를 처리하는 것이 아니고 이벤트가 발생한 객체가 다른 객체에게 이벤트 처리를 위임하는 방식
- 컴포넌트는 출력에만 집중하고 다른 작업은 별도의 객체가 처리하는 것이 유지보수에 유리
이벤트 처리하는 메소드를 확인
- 이 메소드의 매개변수를 이용하면 이벤트가 발생한 객체에 대한 정보를 가져올 수 있습니다.
- 자바에서는 getSource()를 호출하면 이벤트가 발생한 객체에 대한 참조를 리턴받을 수 있습니다.
- 가지고 있는 메소드들이 이벤트별로 다른데 이 메소드들이 이벤트에서 사용할 정보를 리턴해줍니다.
2.이벤트 처리 실습
- 버튼을 누르거나 메뉴를 누르는 경우 또는 TextField에서 Return 키를 누르는 경우를 처리할 때는 ActionListener를 이용해서 처리
- 버튼과 텍스트 필드를 만들고 버튼을 누르면 텍스트 필드에 입력된 내용을 콘솔에 출력
1) Anonymous 클래스를 이용하는 방법
- Frame으로 부터 상속받는 클래스
public class MyWindow extends Frame {
private Button btn;
private TextField tf;
public MyWindow() {
//여러 개의 컴포넌트를 묶어줄 Container 생성
Panel p = new Panel();
//컴포넌트들을 생성
btn = new Button("클릭");
tf = new TextField(30);
//버튼의 이벤트 처리를 위한 ActionListener 인터페이스의 anonymous class 생성
ActionListener listener =
new ActionListener() {
//버튼을 누르거나 텍스트 필드에서 Return 누르거나 메뉴를 누르면 호출되는 메소드
@Override
public void actionPerformed(ActionEvent arg0) {
//입력한 내용 가져오기
String msg = tf.getText();
//출력
System.out.println(msg);
}
};
//btn 에서 Action 이벤트가 발생하면 listener가 대신 처리하도록 위임(Delegation)
btn.addActionListener(listener);
//컴포넌트들을 컨테이너에 배치
p.add(tf);
p.add(btn);
//컨테이너를 윈도우에 배치
add(p);
//Frame 기본 설정
setTitle("이벤트 처리");
setLocation(100,100);
setSize(200,200);
setVisible(true);
}
}
- 별도의 이벤트 처리 클래스를 생성해서 이벤트를 처리
- ActionListener 인터페이스를 implements 한 클래스를 생성 - EventHandler
public class EventHandler implements ActionListener {
private TextField tf;
//생성자 : TextField 1개를 주입받는 생성자
public EventHandler(TextField tf) {
this.tf = tf;
}
@Override
public void actionPerformed(ActionEvent arg0) {
String msg = tf.getText();
System.out.println(msg);
}
}
- MyWindow 클래스의 생성자에서 이벤트 연결
//이벤트 처리를 위한 인스턴스를 생성
EventHandler handler = new EventHandler(tf);
btn.addActionListener(handler);
3.인터페이스를 이용하는 방법
1) 인터페이스를 구현한 클래스를 만들고 인스턴스를 만드는 방법
- 유지보수를 위해서는 이 방식을 권장
- 생성자나 setter 메소드를 이용해서 데이터를 넘겨야 하는 어려움이 있음
2) 인터페이스를 가지고 Anonymous Class를 만드는 방법
- 일반적인 자바(안드로이드) 책에서 많이 사용하는 방법
- 이 방법은 컴포넌트가 구현된 클래스에 만들기 때문에 클래스의 변수 사용이 자유로워서 많이 이용
3) 특수한 인터페이스의 경우는 람다를 이용하는 방법
- Android Studio 는 이 방식으로 최적화
4.Event Routing
여러 개의 이벤트를 하나의 인스턴스가 처리하도록 하는 방법
1개의 이벤트를 1개의 인스턴스가 처리하도록 하면 여러 개의 이벤트를 처리할 때 인스턴스의 개수가 늘어나고 제어하기가 어려워집니다.
이 때는 이벤트 처리 메소드에서 이벤트가 발생한 인스턴스를 구분해서 분기를 해야 합니다.
- awt 나 swing에서는 이벤트 처리 메소드의 매개변수가 getSource()를 호출하면 이벤트가 발생한 객체의 참조를 리턴하기 때문에 이를 이용해서 구분할 수 있고 ActionEvent의 경우는 getActionCommand()를 호출하면 문자열을 리턴해주는데 이 문자열이 버튼의 텍스트입니다.
- getSource()를 사용하는 경우는 배열이나 List 인 경우
이전 Frame에 버튼을 2개 추가해서 이벤트 라우팅 구현 - MyWindow 클래스에서 작업
1) 인스턴스 변수로 버튼을 2개를 추가
private Button btn1, btn2;
2)생성자 메소드에서 버튼 2개를 만들어서 윈도우에 추가
//버튼을 생성해서 패널에 추가
btn1 = new Button("버튼1");
p.add(btn1);
btn2 = new Button("버튼2");
p.add(btn2);
//버튼의 이벤트 처리 - 라우팅을 이용하지 않는 경우
/*
ActionListener event1 = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("버튼1을 클릭했습니다.");
}
};
btn1.addActionListener(event1);
ActionListener event2 = new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println("버튼2를 클릭했습니다.");
}
};
btn2.addActionListener(event2);
*/
//이벤트 라우팅을 이용하는 방법
ActionListener eventRouting =
new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
System.out.println(arg0.getActionCommand() + " 예약");
}
};
btn1.addActionListener(eventRouting);
btn2.addActionListener(eventRouting);
- p를 만들고 난 후에 코드를 추가해야 합니다.
5.ItemEvent
- 체크박스 나 라디오 버튼 이나 콤보박스(Choice)의 선택을 변경하는 경우에 발생하는 이벤트
- ItemListener 인터페이스가 처리
- 이벤트 처리 메소드의 매개변수가 getItem()을 호출하면 어떤 Item에 이벤트가 발생했는지 알 수 있고 getStateChange() 메소드를 호출하면 어떤 상태로 변경되었는지 확인이 가능
6.TextListener
TextField 나 TextArea에서 텍스트의 변경이 발생했을 때를 처리하는 리스너
textValueChanged(TextEvent e) 메소드를 이용해서 처리
텍스트가 변경될 때 상태 변화에 따라 메시지를 출력하거나 유효성을 검사하는 용도로 사용
영문 대소문자 그리고 숫자 및 특수문자가 1개 이상이면 강함이라고 출력
그렇지 않은 경우에는 약함이라고 출력
특수문자는 영문 대소문자가 아니고 숫자도 아니면 특수문자로 판단
//텍스트 필드나 텍스트 에어리어의 문자열이 변경될 때 처리를 위한 인스턴스
TextListener tl = new TextListener() {
@Override
public void textValueChanged(TextEvent arg0) {
//텍스트 필드에 입력된 문자열을 가져오기
String msg = tf.getText();
//대소문자 숫자, 특수문자 개수를 저장할 변수를 생성
int dae = 0;
int so = 0;
int su = 0;
int etc = 0;
//문자열을 문자단위로 접근
for(int i=0; i<msg.length(); i=i+1) {
//앞에서부터 한글자씩 가져오기
char ch = msg.charAt(i);
if(ch >= 'A' && ch <= 'Z') {
dae = dae + 1;
}else if(ch >= 'a' && ch <= 'z') {
so = so + 1;
}else if(ch >= '0' && ch <= '9') {
su = su + 1;
}else {
etc = etc + 1;
}
}
if(dae*so*su*etc != 0 ) {
System.out.println("강함");
}else {
System.out.println("약함");
}
}
};
tf.addTextListener(tl);
7.KeyListener
- 키보드 이벤트를 처리하기 위한 리스너
1) 처리를 위한 메소드
void keyPressed(KeyEvent e): 키보드를 누를 때
void keyReleased(KeyEvent e): 키보드에서 손을 뗄 때
void keyTypes(KeyEvent e): 키보드를 누르고 누른 키가 문자 키일 때 호출되는 메소드
keyPressed 는 키보드 위치 만을 감지를 해서 대소문자 구분을 하지 못했고 keyTypes가 대소문자 구분을 했습니다.
2) KeyEvent 클래스
- 모든 key 값이 상수로 정의되어 있습니다.
- getKeyChar()를 이용해서 누른 문자를 가져올 수 있고 getKeyCode()를 이용해서 누른 키보드의 숫자 값을 가져올 수 있습니다.
3) 방향키를 이용해서 레이블을 움직이고 control + x를 누르면 프로그램 종료하는 윈도우
public class KeyWindow extends Frame {
private Label lbl;
public KeyWindow() {
//컴포넌트들의 위치 변경이나 크기 변경이 가능하도록 레이아웃을 null로 설정
setLayout(null);
//레이블을 생성하고 배치
lbl = new Label("@");
lbl.setLocation(20, 30);
lbl.setSize(15,15);
add(lbl);
//레이블을 1초마다 아래로 5만큼씩 이동하는 스레드
Thread th = new Thread() {
public void run() {
while(true) {
try {
Thread.sleep(1000);
int x = lbl.getLocation().x;
int y = lbl.getLocation().y;
y = y + 5;
lbl.setLocation(x, y);
}catch(Exception e) {}
}
}
};
th.start();
//키보드 이벤트 처리를 위한 인스턴스를 생성
KeyListener listener = new KeyListener() {
//키보드를 눌렀을 때 호출되는 메소드
@Override
public void keyPressed(KeyEvent arg0) {
//조합키 확인 : shift-1, control-2, alt-8
int modifiers = arg0.getModifiers();
//control + X 이면 종료
//control 키가 눌러졌는지 확인
if((modifiers & 2) != 0) {
//별도로 누른 키가 X 인지 확인 - 대소문자를 구분해서 하고자 하는 경우는 getKeyChar()
int key = arg0.getKeyCode();
if(key == KeyEvent.VK_X) {
System.exit(0);
}
}
//System.out.println("아무 키나 누르면 호출됩니다.");
//keyChar는 대소문자 구분 : a -> a, A -> A
//System.out.println(arg0.getKeyChar());
//keyCode는 대소문자 구분 안함 : a->65 A->65
//System.out.println(arg0.getKeyCode());
//현재 레이블의 위치 가져오기
int x = lbl.getLocation().x;
int y = lbl.getLocation().y;
//누른 키보드 값 가져오기
int code = arg0.getKeyCode();
switch(code) {
case KeyEvent.VK_UP:
y = y - 5;
break;
case KeyEvent.VK_DOWN:
y = y + 5;
break;
case KeyEvent.VK_LEFT:
x = x - 5;
break;
case KeyEvent.VK_RIGHT:
x = x + 5;
break;
}
lbl.setLocation(x, y);
}
//키보드에서 손을 뗄 때 호출되는 메소드
@Override
public void keyReleased(KeyEvent arg0) {
//System.out.println("키보드에서 손을 떼면 무조건 호출");
}
//문자키를 눌렀을 때 호출되는 메소드
@Override
public void keyTyped(KeyEvent arg0) {
//System.out.println("문자 키를 눌렀을 때 호출");
}
};
//윈도우에 키보드 이벤트 리스너를 연결
this.addKeyListener(listener);
setTitle("키보드 이벤트");
setLocation(100,100);
setSize(400,400);
setVisible(true);
}
}
8.MouseListener
- 마우스 이벤트를 처리해주는 리스너
- 클릭, 영역에 마우스가 들어온 경우, 영역에서 벗어나는 경우, 마우스는 누를 때, 마우스에서 손을 뗄 때 처리를 위한 메소드가 존재
- MouseEvent 에서는 마우스의 좌표를 리턴해주는 메소드와 클릭 횟수 등을 리턴해주는 메소드가 존재
9.MouseMotionListener
- 마우스를 드래그 할 때를 처리해주는 리스너
- 버튼을 누르고 움직일 때는 위한 Dragged 메소드와 마우스를 움직이면 무조건 호출되는 Moved 메소드가 존재
10.WindowListener
윈도우 이벤트를 처리해주는 리스너
윈도우 관련된 7개의 이벤트 처리 메소드가 존재
윈도우의 종료 버튼을 누를 때 처리를 위한 메소드는 windowClosing
이전 윈도우의 생성자에 종료 버튼을 누를 때 프로그램이 종료되도록 이벤트 처리 코드를 추가
WindowListener windowListener = new WindowListener() {
@Override
public void windowActivated(WindowEvent arg0) {
}
@Override
public void windowClosed(WindowEvent arg0) {
}
//종료 버튼을 누를 때 호출되는 메소드
@Override
public void windowClosing(WindowEvent arg0) {
//프로그램 종료
System.exit(0);
}
@Override
public void windowDeactivated(WindowEvent arg0) {
}
@Override
public void windowDeiconified(WindowEvent arg0) {
}
@Override
public void windowIconified(WindowEvent arg0) {
}
@Override
public void windowOpened(WindowEvent arg0) {
}
};
//윈도우 이벤트 연결
this.addWindowListener(windowListener);
11.이벤트 처리를 Listener 인터페이스를 이용해서 처리하도록 하면 실제 사용하는 메소드는 1개 밖에 없는 인터페이스의 메소드는 전부 추상 메소드라서 반드시 재정의 해야 합니다.
java 의 awt에서는 메소드가 2개 이상인 Listener 들을 Adapter 클래스에 비어있는 내용으로 구현해서 필요한 메소드만 재정의 할 수 있도록 Adapter class를 제공합니다.
Adapter class는 전부 추상 클래스라서 직접 인스턴스를 생성하지 못합니다.
앞의 윈도우 이벤트 처리 구문을 수정
//Listener는 인터페이스라서 모든 메소드를 구현해야 하지만
//Adapter는 추상클래스라서 추상메소드 와 필요한 메소드만 구현하면 됩니다.
WindowAdapter windowListener = new WindowAdapter() {
//종료 버튼을 누를 때 호출되는 메소드
@Override
public void windowClosing(WindowEvent arg0) {
//프로그램 종료
System.exit(0);
}
};
//윈도우 이벤트 연결
this.addWindowListener(windowListener);
'Language_Study > JAVA' 카테고리의 다른 글
[JAVA, App] 18.Stream (0) | 2020.12.27 |
---|---|
[JAVA, App] 17.자바GUI (0) | 2020.12.27 |
[JAVA, App] 15.MutualExclusion (0) | 2020.12.27 |
[JAVA, App] 14.기본API클래스 (0) | 2020.12.27 |
[JAVA, App] 13.Framework (0) | 2020.12.25 |