[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개의 댓글