이벤트 기반 프로그래밍(Event Driven Programming)
- 이벤트 종류
- 사용자의입력:마우스드래그,마우스클릭,키보드누름등
- 센서로부터의 입력, 네트워크로부터 데이타 송수신
- 다른 응용프로그램이나 다른 스레드로부터의 메시지
- 이벤트의 발생에 의해 프로그램 흐름이 결정되는 방식
- 이벤트가 발생하면 이벤트를 처리하는 루틴(이벤트 리스너) 실행
- 프로그램내의 어떤 코드가 언제 실행될지 이벤트 발생에 의해 전적으로 결정
- 반대되는 개념 : 배치 실행(batch programming)
- 프로그램의 개발자가 프로그램의 흐름을 결정하는 방식
이벤트 기반 프로그램의 구조
- 이벤트 리스너 들의 집합
이벤트 처리 순서
- 이벤트 발생(예 :마우스나 키보드의 움직임 혹은 입력)
- 이벤트 객체 생성
- 현재 발생한 이벤트에 대한 정보를 가진 객체
- 이벤트 리스너 찾기
- 이벤트 리스너 호출
- 이벤트 객체가 리스너에 전달됨
- 이벤트 리스너 실행
이벤트 실제 예
자바의 이벤트 기반 GUI 응용프로그램 구성
이벤트소스
- 이벤트를 발생시킨 GUI 컴포넌트
이벤트객체
- 발생한 이벤트에 대한 정보
- 예)이벤트종류,이벤트소스,화면좌표,마우스버튼종류,눌러진키
이벤트 리스너
- 이벤트를 처리하는 코드
- 컴포넌트에 등록되어야 작동 가능
이벤트 분배 스레드
- 동작
- 자바 가상 기계로부터 이벤트의 발생을 통지 받음
- 이벤트 소스와 이벤트 종류 결정
- 적절한 이벤트 객체 생성,이벤트 리스너를 찾아 호출
- 무한 루프를 실행하는 스레드
이벤트 객체란?
- 이벤트가발생할때,발생한이벤트에관한정보를가진객체
- 이벤트 리스너에 전달됨
- 이벤트 리스너 코드에서 이벤트가 발생한 상황을 파악할 수 있게 함
이벤트 객체의 종류
이벤트 객체에 포함된 정보
이벤트 객체가 포함하는 정보
- 이벤트 종류
- 이벤트 소스
- 이벤트가 발생한 화면 좌표
- 이벤트가 발생한 컴포넌트 내 좌표
- 버튼이나 메뉴 아이템에 이벤트가 발생한 경우 버튼이나 메뉴 아이템의 문자열
- 클릭된 마우스 버튼 번호
- 마우스의 클릭 횟수
- 키가눌러졌다면키의코드값과문자값
- 체크박스, 라디오버튼 등과 같은 컴포넌트에 이벤트가 발생하였다면 체크 상태
이벤트에 따라 조금씩 다른 정보 포함
- ActionEvent 객체 : 액션 문자열
- MouseEvent 객체 : 마우스의 위치 정보, 마우스 버튼, 함께 눌러진 키 정보 등
- ItemEvent 객체 : 아이템의 체크 상태
이벤트 소스 알아 내기
- Object EventObject.getSource()
- 발생한 이벤트의 소스 컴포넌트 리턴
- Object 타입으로 리턴하므로 캐스팅하여 사용
- 모든이벤트객체에대해적용
이벤트 객체의 메소드
이벤트 객체와 이벤트 소스
이벤트 리스너란?
- 이벤트를 처리하는 코드, 클래스로 작성
JDK에서 이벤트 리스너 작성을 위한 인터페이스(interface) 제공
- 개발자가 리스너 인터페이스의 추상 메소드 구현
- 이벤트가 발생하면 자바 플랫폼은 리스너 인터페이스의 추상 메소드 호출
- 예) ActionListener 인터페이스
interface ActionListener { // 아래 메소드를 개발자가 구현해야 함 public void actionPerformed(ActionEvent e); // Action 이벤트 발생시 호출됨 }
- 예) MouseListener 인터페이스
interface MouseListener { // 아래의 5개 메소드를 개발자가 구현해야 함 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); // 마우스가 컴포넌트 위에서 내려오는 순간 호출 }
리스너 인터페이스와 메소드
컴포넌트는 다른 이벤트에 대한 리스너를 동시에 가질 수 있다.
- JButton.addActionListener(); // Action 리스너
- JButton.addKeyListener(); // Key 리스너
- JButton.addFocusListener(); // Focus 리스너
컴포넌트는 한 이벤트에 대해 여러개의 리스너를 동시에 가질 수 있다.
- JButton.addActionListener(new MyButtonListener1());
- JButton.addActionListener(new MyButtonListener2());
- JButton.addActionListener(new MyButtonListener3());
- 이때, 리스너는 등록된 반대 순으로 모두 실행된다.
1. 독립 클래스로 작성
- 이벤트 리스너를 완전한 클래스로 작성
- 이벤트리스너를여러곳에서사용할때적합
2. 내부 클래스(inner class)로 작성
- 클래스 안에 멤버처럼 클래스 작성
- 이벤트 리스너를 특정 클래스에서만 사용할 때 적합
3. 익명 클래스(anonymous class)로 작성
- 클래스의 이름 없이 간단히 리스너 작성
- 클래스조차만들필요없이리스너코드가간단한경우에적합
익명 클래스란?
- (클래스 정의 + 인스턴스 생성)을 한번에 작성
new 익명클래스의수퍼클래스이름(생성자의 인자들) { ..................... 멤버 구현 ..................... };
- ActionListener를 구현하는 익명의 이벤트 리스너 작성 예
예제 10-3 : 익명 클래스로 Action 이벤트 리스너 만들기
이벤트 리스너 구현에 따른 부담 해소를 위해
- 리스너 작성시 추상 메소드들을 모두 구현해야 하는 부담
- 마우스 리스너에서 마우스가 눌러지는 경우(mousePressed())만 처리하고자 하는 경우에도 나머지 4 개의 메소드를 모두 구현해야 하는 부담
어댑터 클래스
- 리스너의 모든 메소드가 단순 리턴하도록 구현해 놓은 클래스
- MouseAdapter 예
- 추상 메소드가 하나뿐인 리스너는 어댑터 클래스 없음
- ActionAdapter, ItemAdapter 클래스는 존재하지 않음
=> 당연한 이야기! 추상 메소드가 하나뿐인 리스너는 그 메소드를 사용하기 위해 리스너를 호출할것이기에
사용할 메소드만 구현해주면 됨
예제 10-5 : MouseAdapter 사용하기
키 입력시,다음 세 경우에 Key 이벤트 발생
- 키를 누르는 순간
- 누른 키를 떼는 순간
- 누른 키를 떼는 순간(Unicode 키의 경우에만)
키 이벤트를 받을 수 있는 조건
- 모든 컴포넌트 가능하지만, 현재 포커스(focus)를 가진 컴포넌트
포커스(focus)
- 컴포넌트나 응용프로그램이 키 이벤트를 독점하는 권한
- 컴포넌트에 포커스 설정 방법 : 다음 2 라인의 코드 필요
component.setFocusable(true); // component가 포커스를 받을 수 있도록 설정 component.requestFocus(); // componen에 포커스 강제 지정
- 자바플랫폼마다실행환경의초기화가서로다를수있기때문에다음코드가필요함 component.setFocusable(true);
스윙 프레임이 만들어질 포커스를 주고자 하는 경우
- JFrame의 setVisible(true) 이후에 포커스를 주어야 함
setVisible(true); // 스윙 프레임 출력 component.setFocusable(true); component.requestFocus();
마우스로 컴포넌트를 클릭할 때 포커스 지정하는 방법
- 언제든지 필요할 때 포커스 줄 수 있음
component.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { Component c = (Component)e.getSource(); // 클릭된 컴포넌트 c.setFocusable(true); c.requestFocus(); } }); // 예제 10-8에서 활용하였음
KeyListener의 3 개 메소드
컴포넌트에 키 이벤트 리스너 등록
component.addKeyListener(myKeyListener);
유니코드 키
- 유니코드는 전 세계의 문자에 대한 코드체계
- 문자들에 대해서만 유니 코드 값 정의
- A~Z,a~z,0~9,!,@,&등
- 유니코드 키가 눌러진 경우 이벤트 호출 순서
- keyPressed(), keyTyped(), keyReleased() 순으로 호출
유니코드가 아닌 키
- 문자 키가 아닌 다음 키들(제어키)
<Function>, <Home>, <Up>, <Delete>, <Control>, <Shift>, <Alt> 등
- 정의된 유니코드 값 없음
- 키마다 키 코드 값(가상 키 코드 값)이 정의되어 있음
- 유니코드 키가 아닌 경우 키 이벤트 호출 순서
- keyPressed(), keyReleased() 만 호출됨
가상키
- 유니코드 키든 아니든 모든 키에 자바의 가상 키 코드가 정의되어 있음
- 가상 키 값으로 어떤 키인지 비교 판단 가능
- 가상 키 코드는 KeyEvent 클래스에 상수로 선언
- 키가 입력되면 키 정보를 가진 이벤트 객체 생성 : KeyEvent객체
- KeyEvent 객체가 리스너에 전달됨
1. 키의 문자 코드(유니코드) 알아내기, char KeyEvent.getKeyChar()
- 눌러진 키에 해당하는 문자 코드(유니코드) 리턴
- 눌러진 키가 문자 키인 경우에만 작동
2. 입력된 키의 가상 키 값 알아내기, int KeyEvent.getKeyCode()
- 모든 키에 대해 작동
- 입력된 키를 판별하기 위해 가상키(Virtual Key) 값과 비교
- 가상 키 값은 KeyEvent 클래스의 상수로 정의됨
3. 키 이름 문자열 리턴 String KeyEvent.getKeyText(int keyCode)
- Static 메소드
- 매개변수 keyCode의 코드 값(가상 키)에 해당하는 키의 이름 문자열 리턴
- F1 키의 경우 "F1", Shift 키의 경우 "SHIFT" 등의 문자열 리턴
예제 10-6 : 다양한 KeyEvent와 KeyListener 활용
예제 10-7 : < F1 > 키를 입력받으면 컨텐트팬의 배경을 초 록색으로, % 키를 입력받으면 노란색으로 변경
예제 10-8 : 상(UP), 하(DOWN), 좌(LEFT), 우(RIGHT) 키로 "HELLO" 문자열을 마음대로 움직이기
마우스 이벤트
- 사용자의 마우스 조작에 따라 발생하는 이벤트, 8가지 경우
- 마우스가 눌러진 위치에서 떼어지는 경우 메소드 호출 순서
mousePressed(), mouseReleased(), mouseClicked()
- 마우스가 드래그될 때 호출되는 메소드 호출 순서
mousePressed(), mouseDragged(), mouseDragged(),..., mouseDragged(), mouseReleased()
MouseListener의 5 개의 이벤트를 처리하는 경우
mouseEntered(), mouseExited(), mousePressed(), mouseReleased(), mouseClicked()
마우스 리스너 등록
component.addMouseListener(myMouseListener);
MouseMotionListener의 이벤트도 함께 처리하고자 하는 경우
mouseDragged(), mouseMoved()
마우스 모션 리스너 등록 필요
component.addMouseMotionListener(myMouseMotionListener);
마우스 포인터의 위치
- int getX(), int getY(),
- Point getPoint()
public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); }
입력된 마우스 버튼
- int getButton()
public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON1) System.out.println("Left Button Pressed"); }
마우스 클릭 횟수
- int getClickCount()
public void mouseClicked(MouseEvent e) { \ if(e.getClickCount() == 2) { // 더블클릭을 처리하는 루틴 } }
예제 10-9 : 마우스와 마우스 모션 이벤트 활용
예제 10-10 : 더블클릭 시 컨텐트팬의 배경색 변경
마우스 휠 이벤트
- 마우스 휠이 구를 때마다 발생하는 이벤트
- 이벤트 발생시마다 MouseWheelEvent 객체 생성
MouseWheelListener
- 마우스 휠 이벤트 리스너
- 마우스 휠 이벤트가 발생할 때마다 호출되는 메소드
Public void mouseWheelMoved(MouseWheelEvent e)
- 마우스 휠 리스너 구현
component.addMouseWheelListener(new MouseWheelListener() { public void mouseWheelMoved(MouseWheelEvent e) { // 마우스 휠의 구르는 방향에 따라 이벤트를 처리한다. } });