1. 이벤트 기반 프로그래밍
-
이벤트 기반 프로그래밍(Event Driven Programming)
- 사용자의 입력(마우스 클릭, 키보드 입력 등)이나 센서 입력, 다른 프로그램의 메시지와 같은 ‘이벤트’가 발생했을 때, 프로그램의 흐름이 결정되는 방식
- 이벤트가 발생하면 해당 이벤트를 처리하기 위해 미리 등록된 ‘이벤트 리스너’가 실행
-
이벤트의 종류
- 사용자 입력: 마우스 드래그, 클릭, 키보드 누름 등
- 센서, 네트워크, 다른 프로그램으로부터의 데이터 및 메시지
-
이벤트 처리 순서
- 이벤트 발생 (예: 사용자가 마우스 버튼 클릭)
- 이벤트 객체 생성 (발생한 이벤트의 정보를 담음)
- 이벤트 리스너 탐색 및 호출 (이벤트 소스에 등록된 리스너를 찾음)
- 이벤트 리스너 실행 (이벤트 객체를 인자로 받아 처리)
-
이벤트 관련 용어
- 이벤트 소스: 이벤트를 발생시킨 GUI 컴포넌트
- 이벤트 객체: 발생한 이벤트에 대한 정보
- 이벤트 리스너: 컴포넌트에 등록된 이벤트를 처리하는 코드
- 이벤트 분배 스레드: 무한 루프를 실행하는 스레드
2. 이벤트 객체
-
이벤트 객체
- 이벤트가 발생했을 때, 해당 이벤트에 대한 상세 정보를 담고 있는 객체
- 이 객체는 이벤트 리스너에게 전달되어 이벤트 처리 로직에 사용
-
포함된 정보
- 이벤트 종류 및 소스 (이벤트를 발생시킨 GUI 컴포넌트)
- 화면 및 컴포넌트 내의 좌표 (마우스 이벤트의 경우)
- 클릭된 마우스 버튼 종류, 클릭 횟수
- 눌러진 키의 코드 값 및 문자 값 (키보드 이벤트의 경우)
-
주요 이벤트 객체
ActionEvent: 버튼 클릭, 메뉴 선택 등 액션이 발생했을 때MouseEvent: 마우스 버튼 누름, 뗌, 클릭, 이동, 드래그 등KeyEvent: 키보드의 키를 누르거나 뗄 때ItemEvent: 체크박스나 라디오 버튼의 상태가 변경될 때WindowEvent: 윈도우 창의 상태 변화(열기, 닫기, 활성화 등)가 있을 때
3. 이벤트 리스너
-
이벤트 리스너(Event Listener)
- 특정 이벤트가 발생했을 때 이를 처리하는 코드를 담고 있는 클래스
- JDK는 이벤트 리스너 작성을 위해 인터페이스를 제공하며, 개발자는 이 인터페이스의 추상 메소드를 구현한다.
-
주요 리스너 인터페이스
ActionListener:actionPerformed()메소드를 구현하여ActionEvent를 처리한다.MouseListener:mousePressed(),mouseReleased(),mouseClicked()등 5개의 메소드를 구현하여 마우스 이벤트를 처리한다.KeyListener: keyPressed(), keyReleased(), keyTyped() 3개의 메소드를 구현하여 키보드 이벤트를 처리한다.
-
작성 방법
- 독립 클래스: 별도의 파일로 리스너 클래스를 작성하며, 여러 곳에서 재사용할 때 유용하다.
- 내부 클래스(Inner class): 특정 클래스 내부에 멤버처럼 리스너 클래스를 작성하며, 해당 클래스에서만 사용할 때 적합하다.
- 익명 클래스(Anonymous class): 이름 없이 클래스를 정의하고 동시에 객체를 생성하는 방식으로, 코드가 간단할 때 유용하다.
3.1. 예제
- 예제 10-1: 독립 클래스 방식
ActionListener를 구현하는MyActionListener클래스를 별도의 파일로 만든다.- 여러 GUI 컴포넌트에서 재사용이 필요할 때 유용한 구조이다.
public class IndepClassListener extends JFrame {
public IndepClassListener() {
// ...
}
}
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
}
}- 예제 10-2: 내부 클래스 방식
ActionListener를 구현하는MyActionListener클래스를 GUI를 생성하는JFrame클래스 내부에 정의한다.- 외부 클래스의 멤버 변수나 메소드에 쉽게 접근할 수 있는 장점이 있다. 예제에서는 버튼의 텍스트로 프레임의 제목을 변경하는 코드가 추가되었다.
public class InnerClassListener extends JFrame {
InnerClassListener() {
// ...
}
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
// InnerClassListener의 멤버나 JFrame의 멤버를 호출할 수 있다.
InnerClassListener.this.setTitle(b.getText());
// 프레임 타이틀에 버튼 문자열을 출력한다.
}
}
}- 예제 10-3: 익명 클래스 방식
- 클래스 이름 없이, 리스너를 추가하는 코드(
addActionListener) 안에서 직접 클래스를 정의하고 객체를 생성한다. - 코드가 간결하며, 해당 이벤트 처리 로직이 한 번만 사용될 경우에 적합하다.
- 클래스 이름 없이, 리스너를 추가하는 코드(
public class AnonymousClassListener extends JFrame {
public AnonymousClassListener() {
// ...
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource();
if (b.getText().equals("Action"))
b.setText("액션");
else
b.setText("Action");
setTitle(b.getText());
}
});
}
}- 예제 10-4: MouseListener를 이용한 문자열 이동
MouseListener인터페이스를 구현하여 마우스 이벤트를 처리한다.mousePressed메소드에서 마우스가 클릭된 좌표를 얻어와JLabel의 위치를 변경한다.MouseListener의 모든 추상 메소드(총 5개)를 반드시 구현해야 하므로, 사용하지 않는 메소드들은 빈 채로 둔다.
public class MouseListenerEx extends JFrame {
public MouseListenerEx() {
// ...
}
class MyMouseListener implements MouseListener {
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
la.setLocation(x, y);
}
}
}4. Adapter 클래스
-
어댑터(Adapter) 클래스
- 리스너 인터페이스의 모든 추상 메소드를 빈 상태로 미리 구현해 놓은 클래스
MouseListener처럼 여러 메소드를 구현해야 하는 인터페이스의 경우, 어댑터 클래스를 상속받으면 원하는 메소드만 오버라이딩(재정의)하여 사용할 수 있어 코드 작성이 간결해진다.
-
예시:
MouseAdapter는MouseListener,MouseMotionListener,MouseWheelListener인터페이스를 구현한 클래스이다. -
주의:
ActionListener나ItemListener와 같이 추상 메소드가 하나뿐인 인터페이스는 대응하는 어댑터 클래스가 없다.
4.1. 예제
- 예제 10-5: MouseAdapter를 이용한 리팩토링
- 예제 10-4를
MouseAdapter클래스를 상속받아 개선한 버전 MouseAdapter는MouseListener의 메소드들이 미리 구현되어 있으므로, 필요한mousePressed메소드만 오버라이딩(재정의)하면 되어 코드가 더 간결해진다.
- 예제 10-4를
public class MouseAdapterEx extends JFrame {
public MouseAdapterEx() {
// ...
}
class MyMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
la.setLocation(x, y);
}
}
}5. KeyEvent와 KeyListener
키보드 입력 시
KeyEvent가 발생하며, 이를 처리하기 위해KeyListener를 사용한다.
-
포커스(Focus)
- 컴포넌트가 키 이벤트를 받으려면 포커스를 가지고 있어야 한다.
component.setFocusable(true);와component.requestFocus();코드를 사용하여 포커스를 설정할 수 있다.
-
키의 종류
- 유니코드 키
- A-Z, 0-9 등 문자에 해당하는 키
keyPressed(),keyTyped(),keyReleased()순서로 이벤트가 발생한다.
- 유니코드가 아닌 키
- F1, Home, Shift 등 제어 키
keyPressed(),keyReleased()이벤트만 발생한다.
- 유니코드 키
-
입력된 키 판별
char KeyEvent.getKeyChar()- 입력된 문자의 유니코드 값을 리턴한다.
- (문자 키에만 해당)
int KeyEvent.getKeyCode()- 모든 키에 대해 정의된 가상 키(Virtual Key) 코드를 리턴한다.
- (예:
KeyEvent.VK_F1,KeyEvent.VK_UP)
String KeyEvent.getKeyText()- 가상 키 코드에 해당하는 문자열을 리턴한다.
- (예: “F1”, “Shift”)
5.1. 예제
- 예제 10-6: 다양한 KeyEvent 정보 출력
- 키보드를 누를 때마다 해당 키의 키 코드(
getKeyCode), 유니코드 문자(getKeyChar), 그리고 키의 이름(getKeyText)을 화면의 레이블에 출력한다. - 이를 통해 키 이벤트로부터 어떤 정보를 얻을 수 있는지 보여준다.
- 키보드를 누를 때마다 해당 키의 키 코드(
public class KeyListenerEx extends JFrame {
public KeyListenerEx() {
// ...
}
class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
char keyChar = e.getKeyChar();
keyMessage[0].setText(Integer.toString(keyCode));
keyMessage[1].setText(Character.toString(keyChar));
keyMessage[2].setText(e.getKeyText(keyCode));
}
}
}-
예제 10-7: 특정 키 입력으로 배경색 변경
<F1>키를 누르면 컨텐트팬의 배경색이 초록색으로,%키를 누르면 노란색으로 변경된다.<F1>과 같은 기능 키는getKeyCode()로,%와 같은 문자 키는getKeyChar()로 구분하여 처리하는 방법을 보여준다.
-
예제 10-8: 방향키로 문자열 이동
- 상(UP), 하(DOWN), 좌(LEFT), 우(RIGHT) 방향키를 이용하여 “HELLO” 문자열을 10픽셀씩 이동시킨다.
keyPressed메소드 안에서switch문을 사용해 눌린 키의 코드(getKeyCode)를 확인하고 각 방향키에 맞는 위치 이동 로직을 수행한다.
6. MouseEvent와 MouseListener
마우스 조작에 따라
MouseEvent가 발생하며, 이를 처리하기 위해MouseListener와MouseMotionListener를 사용한다.
-
리스너 종류
MouseListener- 마우스 버튼 누름(
mousePressed) - 마우스 버튼 뗌(
mouseReleased) - 마우스가 컴포넌트를 클릭(
mouseClicked) - 마우스가 컴포넌트에 진입(
mouseEntered) - 마우스가 컴포넌트에서 이탈(
mouseExited)
- 마우스 버튼 누름(
MouseMotionListener- 마우스가 이동하는 동안(
mouseMoved) - 마우스가 드래그하는 동안(
mouseDragged) - 마우스 휠이 구르는 동안(
mouseWheelMoved)
- 마우스가 이동하는 동안(
-
마우스 정보 얻기
getX(),getY(),getPoint()- 이벤트가 발생한 마우스 포인터의 위치를 얻는다.
getButton()- 눌러진 마우스 버튼을 판별한다. (예:
MouseEvent.BUTTON1은 왼쪽 버튼)
- 눌러진 마우스 버튼을 판별한다. (예:
getClickCount()- 마우스 클릭 횟수를 얻어 더블클릭 등을 감지할 수 있다.
6.1. 예제
-
예제 10-9: 마우스 및 마우스 모션 이벤트 활용
MouseListener와MouseMotionListener를 모두 구현하여 다양한 마우스 이벤트를 처리한다.- 기능
- 마우스가 컴포넌트 안으로 들어오면(
mouseEntered) 배경색이 하늘색으로 변경된다. - 컴포넌트 밖으로 나가면(
mouseExited) 배경색이 노란색으로 변경된다. - 마우스를 누르거나(
mousePressed), 떼거나(mouseReleased), 드래그(mouseDragged), 이동(mouseMoved)할 때마다 현재 좌표를 레이블에 표시한다.
- 마우스가 컴포넌트 안으로 들어오면(
-
예제 10-10: 더블클릭으로 배경색 변경
- 마우스를 더블클릭할 때마다 컨텐트팬의 배경색이 랜덤한 색으로 변경된다.
mouseClicked이벤트 내에서getClickCount()메소드의 반환 값이 2인지 확인하여 더블클릭을 감지한다.