이벤트 처리 순서
이벤트가 발생함
이벤트가 발생하면 이벤트 객체가 생성됨
- 이벤트 객체 : 현재 발생한 이벤트에 대한 정보를 가진 객체
이벤트 리스너를 호출
- 이벤트 리스너 : 이벤트를 처리하도록 만들어진 코드
- 발생한 이벤트를 처리할 특정 이벤트 리스너를 찾고 이벤트 객체를 전달함
이벤트 리스너 실행
- 이벤트 리스너가 이벤트 처리를 해준다.
이벤트 용어정리
이벤트 소스 : 이번 이벤트를 발생시킨 컴포넌트
이벤트 객체 : 이번에 발생한 이벤트에 대한 정보를 담은 객체
- 이벤트 객체가 포함하는 정보 ex. 이벤트 종류, 이벤트 소스, 마우스 클릭 횟수, 이벤트 발생한 컴포넌트 내 좌표 등등
이벤트 리스너 : 이벤트를 처리하는, 즉 받아온 이벤트를 어떻게 동작시킬지에 대한 코드
이벤트 분배 스레드 : 이벤트에 대한 모든 동작을 수행하게 도와주는 놈
이벤트 소스 알아내기
EventObject.getSource() : 어떤 컴포넌트에서 이벤트가 발생했는지 그에 해당하는 참조자를 리턴해줌
리스너 코드들은 항상 이벤트 객체를 받게 되어있다.
ex. try-catch 구문과 유사. try 에서 이벤트 객체를 던지면 catch 문에서, 즉 리스너 코드가 이벤트 객체를 받음.매개변수 e 로 이벤트 객체를 받은 경우, e.getSource() 로 어떤 컴포넌트에서 이벤트가 발생했는지 그에 해당하는 참조자를 리턴해줌
리턴타입 : Object => 실제 사용시에 캐스팅을 해서 사용할것!
이벤트 종류
이벤트 객체종류
- KeyEvent
- 이벤트 소스 : Component (컴포넌트)
- 이벤트가 발생하는 경우 : 키가 눌러지거나 키가 떼어질 때
- MouseEvent
- 이벤트 소스 : Component (컴포넌트)
- 이벤트가 발생하는 경우 : 마우스 관련한 동작
- ActionEvent
- 이벤트 소스 : JButton
- 이벤트가 발생하는 경우 : 어떤 행동(Action) 을 유발하는 이벤트 종류가 발생한 경우
- Action 예시 :
버튼을 클릭하는 것, 엔터키 누르는 것
=> Action 을 담당하는 일부 컴포넌트만 ActionEvent가 발생함
- Action 예시 :
버튼을 클릭하는 것, 엔터키 누르는 것
이벤트 리스너
- 이벤트에 대한 동작(처리)를 코드, 클래스를 작성
ex. 버튼을 클릭했을 때 그 버튼한테 등록된 MouseEvent 이벤트 리스너를 찾아서, 그 리스너 안쪽에다 화면에 변경되는 내용을 작성하면 된다.
- 각 이벤트 객체별로 담당하는 이벤트들이 있다.
- 이벤트마다 어느정도 동작이 정의가 되어있음. 따라서 자바는 각 이벤트 종류별로 인터페이스(interface) 를 제공한다.
=> 이 인터페이스 리스너에 대해 클래스로 각 추상메소드를 오버라이딩을 하면서, 구현을 해서 동작을 정의시키면 된다.
- 이벤트마다 어느정도 동작이 정의가 되어있음. 따라서 자바는 각 이벤트 종류별로 인터페이스(interface) 를 제공한다.
ex. ActionListener 인터페이스
- Action
이벤트를 처리할 수 있는 리스너 코드를 만들떄,
Action 이벤트를 처리할 수 있는 클래스를 만들면서 아래와 같이 자바에서 제공하는 ActionListener 인터페이스를 구현해주면 된다!
ex. MouseListener 인터페이스
- 마우스 이벤트에 대한 동작을 처리하기 위해 리스너 코드를 위해 아래 인터페이스를 재정의해야한다!
리스너 인터페이스 종류및 추상메소드
- 더 자세한건 굳이 알필요 없을듯
컴포넌트에 리스너 등록하기
리스너에 대한 오버라이딩 과정이 완료되면, 우리가 원하는 컴포넌트에 해당 리스너를 연결해줘야한다.
컴포넌트에 리스너 등록하는 과정은 아래와 같은 형태를 선언하면 된다.
형태1 : (컴포넌트).add(리스너 이름)();
형태2 : (컴포넌트).add(리스너 이름)(객체);
=> 객체 : 이 리스너 처리코드를 가지고 있는 클래스의 객체
ex1.
JButton.addActionListener(); JButton.addKeyLisener(); JButton.addFocusListener();ex2.
JButton.addActionListener(new MyButtonLisener1()); JButton.addActionListener(new MyButtonLisener2()); JButton.addActionListener(new MyButtonLisener3());이벤트 리스너 작성 방법
그렇다면 인터페이스를 구현하는 이벤트 리스너를 클래스로 작성할때 어떻게 만들 수 있는지 더 자세히 알아보자.
1. 독립 클래스로 작성
- 즉, JFrame 를 상속받아서 프레임에 관한 클래스를 만들었는데, 이 클래스와 독립적으로 별개의 클래스를 바깥에 정의한다.
2. 내부 클래스(안쪽 클래스)로 작성
- 프레임 클래스안에 정의하기
3. 익명 클래스로 작성
예제1 - 독립 클래스
아래와 같이 Action 이벤트(버튼을 클릭하는 액션)에 대한 처리를해줄수 있는 ActionListener 인터페이스를 재정의한다.
재정의할 메소드가 actionPerformed() 1개이다.
이때 actionPerformed() 의 인자로 들어가는
ActionEvent e 는 이벤트 객체이다.
이벤트 객체 e 는 방금 버튼을 클릭한 것에 대한 이벤트 정보를 모두 가지고 있다!
- 재정의 내용 : 버튼에 대한 속성을 바꿈
- 여러개의 버튼 중에서 클릭된 버튼이(클릭이라는 액션이 발생한 버튼이) 어떤 녀석인지 얻어오기 위해 getSource() 이용해서 컴포넌트의 참조자를 얻어옴
- 얻어온 정보를, 즉 버튼 이벤트가 발생한 참조자를 b 에 저장
- 버튼 b에 쓰인 글자(getText()) 가 "Action" 이라면 버튼의 문자열을 "액션"으로 변경
그리고 아래처럼 버튼(컴포넌트) 에 앞서 정의한 리스너인 ActionListener 를
등록해준다.
=> 버튼을 누르는 행위 (액션) 이 발생하면, 정의한 리스너의 내용이 수행된다.
전체코드
실행결과
- 버튼을 누르는 액션 이벤트가 발생할때마다 버튼안에 들어있는 텍스트가 바뀜
예제2 - 내부 클래스(안쪽 클래스) 로 이벤트 리스너 만들기
잠깐, 복습!) 안쪽 클래스에서 "바깥클래스.this.메소드()" 형식을 호출하면 이는 바깥클래스의 메소드가 호출되는 것이였다.
익명 클래스
- (클래스 정의 + 인스턴스 생성) 을 한번에 작성
형태 :
new 익명클래스의부모클래스(생성자의 인자들){
...
익명 클래스의 정의부
...
};
ex. 원래는 아래처럼 리스너 클래스를 만들고 addActionListener() 메소드로 리스너를 등록해줬었다.
// 익명 클래스 사용안하고 그냥 만든 리스너 클래스인 MyActionListener class MyActionListener implements ActionListener{ public void actionPerformed(ActionEvent e){ ... } } b.addActionListner(new MyActionListener()); // 리스너 객체 등록반면 아래와 같이 익명 클래스로 익명 객체 만들고 바로 등록가능하다.
b.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent e){ ... } });예제
리스너 객체를 익명 객체로 만들고, 그 익명객체를 addActionListener() 를 통해 해당 버튼에 바로 등록해줌
MouseListener 리스너
마우스로 문자열 이동시키기
- Hello 라는 문자열을 마우스 커서가 있는 곳으로 옮길 수 있다.
- 마우스를 클릭하면 옮겨짐
마우스를 누르는 행위에 대한 이벤트를 처리하기 위해 MouseListener 리스너 인터페이스를 구현한다.
- 그 중에서 눌러지는 순간 mousePressed() 의 재정의한 내용이 실행되도록 한다.
MouseListener 인터페이스에서 mousePressed() 메소드만 재정의하고 나머지 4개 메소드는 따로 기능을 추가해서 재정의하지 않는다.
- 마우스를 누른 순간에 발생하는 이벤트에 대해서만 정의하면 되기때문!
위와 같이 이벤트가 발생한 x, y좌표를 getX() 와 getY() 로 얻어온다.
그리고 "hello" 라고 문자열이 적혀있던 레이블 객체 la 를 (x,y) 좌표로 이동시키기 위해 setLocation() 속성을 활용한다!
그리고 이벤트가 발생하는 컴포넌트가 컨텐트팬(ContentPane) 이기 떄문에
( 컨텐트팬도 컴포넌트이다! 컨테이기도 하기만 컴포넌트이기도 함)
리스너 객체 컨텐트팬에 등록해준다!
어댑터(Adapter) 클래스
- 각 이벤트의 리스너 인터페이스에 대해 빈껍대기 형태로 구현을 다 해놓은 리스너 클래스
- 이미 리스너 인터페이스의 추상 메소드들을 모두 구현을 다 해놔서, 이 어댑터 클래스를 상속받고 빈 껍대기 형태로 다 재정의 되어있는 메소드들 중에서 필요한 기능의 메소드만 재정의해서 사용하면 된다!
=> "어댑터 클래스를 상속" 받는 것이므로, implements 가 아니라 extends 키워드를 사용하자!
- 리스너 클래스를 더 편하게 구현하게 해주는 클래스
=> 내가 리스너 인터페이스에서 재정의할 필요없는 메소드들도 빈껍대기 형태가 되더라도 재정의 해줘했었음!
ex. MouseAdapter 어댑터 클래스 정의내용
주의 : 추상 메소드가 하나뿐인 리스너는 어댑터 클래스가 없다!!!!
=> ActionAdapter 라는 클래스는 존재하는 존재하지 않는다.
따라서 ActionListener() 인터페이스를 구현해야함!
예제1
왼쪽은 앞서 배웠던 인터페이스 구현방법이고, 오른쪽은 지금 배우는 어댑터 클래스이다.
보듯이 어댑터는 필요한 부분만 재정의하면 된다.