[JAVA] GUI (2) - 이벤트처리

msung99·2022년 5월 31일
0
post-thumbnail

이벤트 처리 순서

  1. 이벤트가 발생함

  2. 이벤트가 발생하면 이벤트 객체가 생성됨

    • 이벤트 객체 : 현재 발생한 이벤트에 대한 정보를 가진 객체
  3. 이벤트 리스너를 호출

    • 이벤트 리스너 : 이벤트를 처리하도록 만들어진 코드
    • 발생한 이벤트를 처리할 특정 이벤트 리스너를 찾고 이벤트 객체를 전달함
  4. 이벤트 리스너 실행

    • 이벤트 리스너가 이벤트 처리를 해준다.

이벤트 용어정리

  1. 이벤트 소스 : 이번 이벤트를 발생시킨 컴포넌트

  2. 이벤트 객체 : 이번에 발생한 이벤트에 대한 정보를 담은 객체

    • 이벤트 객체가 포함하는 정보 ex. 이벤트 종류, 이벤트 소스, 마우스 클릭 횟수, 이벤트 발생한 컴포넌트 내 좌표 등등
  3. 이벤트 리스너 : 이벤트를 처리하는, 즉 받아온 이벤트를 어떻게 동작시킬지에 대한 코드

  4. 이벤트 분배 스레드 : 이벤트에 대한 모든 동작을 수행하게 도와주는 놈


이벤트 소스 알아내기

EventObject.getSource() : 어떤 컴포넌트에서 이벤트가 발생했는지 그에 해당하는 참조자를 리턴해줌

  • 리스너 코드들은 항상 이벤트 객체를 받게 되어있다.
    ex. try-catch 구문과 유사. try 에서 이벤트 객체를 던지면 catch 문에서, 즉 리스너 코드가 이벤트 객체를 받음.

  • 매개변수 e 로 이벤트 객체를 받은 경우, e.getSource() 로 어떤 컴포넌트에서 이벤트가 발생했는지 그에 해당하는 참조자를 리턴해줌

  • 리턴타입 : Object => 실제 사용시에 캐스팅을 해서 사용할것!


이벤트 종류

이벤트 객체종류

  1. KeyEvent
  • 이벤트 소스 : Component (컴포넌트)
  • 이벤트가 발생하는 경우 : 키가 눌러지거나 키가 떼어질 때
  1. MouseEvent
  • 이벤트 소스 : Component (컴포넌트)
  • 이벤트가 발생하는 경우 : 마우스 관련한 동작
  1. ActionEvent
  • 이벤트 소스 : JButton
  • 이벤트가 발생하는 경우 : 어떤 행동(Action) 을 유발하는 이벤트 종류가 발생한 경우
    • Action 예시 : 버튼을 클릭하는 것, 엔터키 누르는 것
      => Action 을 담당하는 일부 컴포넌트만 ActionEvent가 발생함

이벤트 리스너

  • 이벤트에 대한 동작(처리)를 코드, 클래스를 작성

ex. 버튼을 클릭했을 때 그 버튼한테 등록된 MouseEvent 이벤트 리스너를 찾아서, 그 리스너 안쪽에다 화면에 변경되는 내용을 작성하면 된다.

  • 각 이벤트 객체별로 담당하는 이벤트들이 있다.
    • 이벤트마다 어느정도 동작이 정의가 되어있음. 따라서 자바는 각 이벤트 종류별로 인터페이스(interface) 를 제공한다.
      => 이 인터페이스 리스너에 대해 클래스로 각 추상메소드를 오버라이딩을 하면서, 구현을 해서 동작을 정의시키면 된다.

ex. ActionListener 인터페이스

  • Action 이벤트를 처리할 수 있는 리스너 코드를 만들떄,
    Action 이벤트를 처리할 수 있는 클래스를 만들면서 아래와 같이 자바에서 제공하는 ActionListener 인터페이스를 구현해주면 된다!
interface ActionListener{     // 아래 메소드를 개발자가 구현해야함
  public void actionPerformed(ActionEvent e);  // => 이 메소드 하나만 재정의 해주면 된다.
}

ex. MouseListener 인터페이스

  • 마우스 이벤트에 대한 동작을 처리하기 위해 리스너 코드를 위해 아래 인터페이스를 재정의해야한다!
// 5개의 추상메소드 모두 재정의 해줄것!

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); // 마우스가 컴포넌트 위에서 내려오는 순간 호출
}

리스너 인터페이스 종류및 추상메소드

  • 더 자세한건 굳이 알필요 없을듯



컴포넌트에 리스너 등록하기

  • 리스너에 대한 오버라이딩 과정이 완료되면, 우리가 원하는 컴포넌트에 해당 리스너를 연결해줘야한다.

  • 컴포넌트에 리스너 등록하는 과정은 아래와 같은 형태를 선언하면 된다.

형태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

왼쪽은 앞서 배웠던 인터페이스 구현방법이고, 오른쪽은 지금 배우는 어댑터 클래스이다.

보듯이 어댑터는 필요한 부분만 재정의하면 된다.

예제2

profile
블로그 이전했습니다 🙂 : https://haon.blog

0개의 댓글