---
title: "Java 정리 21"
date: "2018-12-11"
tags: ["Java"]
status: archived
verified: false
---

## Java 정리 21 - AWT Event Handling

---

### Event Handling

* **사용자의 동작에 따른 처리코드를 만들어두고 그 코드를 실행하는 것**
* **AWT와 Swing**에서 **같이 사용**할 수 있다.
* **java.awt.event 패키지**에서 관련 클래스, interface 제공
* interface가 하나 이상의 추상 method를 가진다면 사용의 편의성을 위해 **~Adapter Class**를 제공

![01](/md/legacy-assets/java/21/01.webp)

---

### 이벤트 처리를 Is-A 관계로 처리하는 방법

* **디자인과 이벤트 처리를 하나의 클래스안에서 처리한다.**
  * 값에 대한 사용이 편하다.

![02](/md/legacy-assets/java/21/02.webp)

1. 한 클래스에서 상속으로 Frame을 받고 구현으로 OOOListener를 처리
2. 이벤트처리와 관련있는 Component를 선언
3. Component를 생성
4. 컴포넌트가 이벤트를 발생할 수 있도록 등록

```java
// 1. 한 클래스에서 상속으로 Frame을 받고 구현으로 OOOListener를 처리
public class Test extends Frame implements ActionListener { ... }

// 2. 이벤트처리와 관련있는 Component를 선언
Button btn;

// 3. Component를 생성
public Test() {
    btn = new Button();
}

// 4. 컴포넌트가 이벤트를 발생할 수 있도록 등록
// ooo.addOOOListener(이벤트가발생했을때처리될객체);
btn.addActionListener(this); 
// 이벤트가 등록되고 이벤트가 발생하면 입력된 객체의 Override된 추상 method가 호출

// 5. btn 컴포넌트의 이벤트 발생시 Override된 메소드 수행
// ActionListner의 abstract method Override
@Override
public void actionPerformed(ActionEvent ae) {
    // 이벤트가 발생했을 때 처리
}
```

![03](/md/legacy-assets/java/21/03.webp)

```java
/**
* ActionEvent를 사용한 Is-A 관계로 이벤트를 처리하는  방법
* 디자인과 이벤트 처리를 하나의 클래스안에서 처리한다.
* (값에 대한 사용이 편하다.)
*/
// 1. 상속으로 Frame을 처리하고, 구현으로 Event Handling  객체를 처리
@SuppressWarnings("serial")
public class EventHandlingIsA extends Frame implements ActionListener {
  
  // 2. 이벤트 처리와 관련이 있는 Component 선언
  private Button btn;
  
  public EventHandlingIsA() {
    super("Is-A 관계로 이벤트 처리방법");
    // 3. Component 생성
    btn = new Button("클릭");
    
    // 4. 생성된 컴포넌트가 이벤트를 발생시킬 수 있도록이벤트에 등록
    btn.addActionListener(this); 
    // Arguments로 입력된 객체의 Override된 method가 호출된다.
    
    Panel panel = new Panel();
    panel.add(btn);
    
    // 5. 생성된 컴포넌트를 배치
    add(BorderLayout.CENTER, panel);
    
    // 6. 윈도우 컴포넌트의 크기를 설정
    setBounds(400, 200, 300, 300);
    
    // 7. 사용자에게 보여주기 (가시화)
    setVisible(true);
    
    // 8. 종료처리
    addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        dispose();
      }
    });
  }
      
  @Override
  public void actionPerformed(ActionEvent e) {
    System.out.println("버튼이 클릭되었습니다.");
    dispose();
  }
  
  public static void main(String[] args) {
    new EventHandlingIsA();
  }
}
```

![04](/md/legacy-assets/java/21/04.webp)

---

### 이벤트처리를 Has-A 관계로 처리하는 방법

* **디자인과 이벤트처리 코드를 분리할 수 있다.**
  * 클래스가 늘어난다.
  * 값 넘기기 어렵다.
  * 에러처리가 복잡해진다.

![05](/md/legacy-assets/java/21/05.webp)

* **Design 클래스**

1. Frame 상속받는 클래스 생성
2. 이벤트 관련 Component를 선언
3. 컴포넌트 생성
4. 이벤트 처리객체 생성하고 Has-A관계 설정
5. 이벤트 등록

```java
// 1 . Frame 상속받는 클래스 생성
public class Test extends Frame { ... }

// 2. 이벤트 관련 Component를 선언
Button btn;

// 3. 컴포넌트 생성
public Test() {
    btn = new Button();
}

// 4. 이벤트 처리객체 생성하고 Has-A관계 설정
TestImpl ti = new TestImpl(this);

// 5. 이벤트 등록
btn.addActionListener(ti);
```

* **Event 클래스**

1. OOOListener를 구현하는 클래스 생성
2. 디자인 클래스를 Has-A 관계로 가지고 사용할 수 있도록 선언
3. 생성자에서 디자인 클래스를 받는다.
4. 추상 method Override

```java
// 1. OOOListener를 구현하는 클래스 생성
public class TestImpl implements ActionListener { ... }

// 2. 디자인 클래스를 Has-A 관계로 가지고 사용할 수 있도록 선언
private Test t;

// 3. 생성자에서 디자인 클래스를 받는다.
public TestImpl (Test t) {
    this.t = t;
}

// 4. 추상 method Override
public void actionPerformed(ActionEvent e) { 
    // 이벤트가 발생했을 때 처리
}
```

![06](/md/legacy-assets/java/21/06.webp)

```java
/**
* Has-A 관계의 이벤트 처리
* 디자인과 이벤트처리 코드를 분리하여 코드의 복잡도를  낮출 수 있다.
*/
// 1. 윈도우 컴포넌트를 상속
@SuppressWarnings("serial")
public class Design extends Frame {
  // 2. 이벤트처리와 관련있는 Component를 선언
  private Button btn;
  
  public Design() {
    super("디자인");
    // 3. 컴포넌트 생성
    btn = new Button("클릭");
    
    // 4. 배치
    Panel panel = new Panel();
    panel.add(btn);
    
    add(BorderLayout.CENTER, panel);
    
    // 5. 이벤트 등록
    // 이벤트 처리 객체 생성하고 Has-A 관계설정
    EventHandlingHasA ehha = new  EventHandlingHasA(this);
    System.out.println("생성된 디자인 객체 "+this);
    
    // 컴포넌트에 이벤트를 등록
    // 버튼에서 이벤트가 발생하면 ehha객체의  Override된 method에서
    // 이벤트를 처리
    btn.addActionListener(ehha);
    
    // 6. 윈도우 크기 설정
    setBounds(100,100,400,300);
    
    // 7. 가시화
    setVisible(true);
    // 8. 종료처리
    addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        dispose();
      }
    });
  }
  
  public Button getButton() {
    return btn;
  }
  
  public static void main(String[] args) {
    new Design();
  }
}
```

```java
/**
* Has-A 관계로 이벤트 처리
*/
// 1. 이벤트 처리 객체를 구현
public class EventHandlingHasA implements ActionListener  {

  // EventHandlingHasA는 Design을 가지고 있다.
  // 2. Has-A 관계로 저장하고 사용할 객체 선언
  private Design design;
  
  public EventHandlingHasA(Design design) {
    this.design = design;
  }
  
  @Override
  // 3. abstract method를 Override
  public void actionPerformed(ActionEvent e) {
    // 이벤트가 발생했을 때 처리할 코드
    System.out.println("전달받은 Design객체 :  "+design);
    design.dispose();
  }
}
```

![07](/md/legacy-assets/java/21/07.webp)

---

### 이벤트처리를 inner class로 처리하는 방법

* **디자인에 해당하는 이벤트처리 코드가 매우 적거나 특정디자인에 해당하는 이벤트만 처리할 때**
  * 디자인 클래스안에서 **여러 이너 클래스**로 이벤트를 구분하여 처리가능

1. 윈도우 컴포넌트를 상속
2. 이벤트 처리와 관계된 컴포넌트 선언
3. 생성
4. 이벤트를 처리하기 위한 inner class를 작성
5. 추상 메소드 Override
6. 이벤트 등록

```java
// 1. 윈도우 컴포넌트를 상속
public class Test extends Frame { ... }

// 2. 이벤트 처리와 관계된 컴포넌트 선언
Button btn;

// 3. 생성
public Test() {
    btn = new Button("버튼");
}

// 4. 이벤트를 처리하기 위한 inner class를 작성
public class Inner implements ActionListener {

// 5. 추상 메소드 Override
  @Override
  public void actionPerformed(ActionEvent e) {
    // 이벤트가 발생했을 때 처리할 코드 
  }
}

// 6. 이벤트 등록
// Inner Class를 객체화
Test.Inner in = this.new Inner();

// Component가 이벤트를 발생할 수 있도록 등록
btn.addActionListener(in);
```

```java
/**
* inner class를 사용한 이벤트 처리 :
* 디자인에 해당하는 이벤트처리 코드 코드가 매우 적거나
* 특정디자인에 해당하는 이벤트만 처리할 때
*/
// 1. 윈도우 컴포넌트를 상속
public class EventHandlingInnerClass extends Frame {
  
  // 2. 이벤트처리 관련 컴포넌트를 객체화
  private Button btn;
  
  public EventHandlingInnerClass() {
    super("Inner class로 이벤트 처리");
    
    // 3. 컴포넌트 생성
    btn = new Button("클릭");
    
    // 4. 배치
    Panel panel = new Panel();
    panel.add(btn);
    add(BorderLayout.CENTER, panel);
    
    // 5. 이벤트 등록
    // inner class 생성.
    EventHandlingInnerClass.InnerActionImpl iai =
              this.new InnerActionImpl();
    
    // 컴포넌트에 이벤트에 등록
    btn.addActionListener(iai);
    
    // 6. 윈도우 크기 설정
    setBounds(100, 100, 300, 300);
    // 7. 가시화
    setVisible(true);
    addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        dispose();
      }
    });
  }
  
  public Button getBtn() {
      return btn;
  }
  //////////////// inner class 시작 //////////////////
  // 5-1. inner class로 이벤트처리 리스너를 구현
  public class InnerActionImpl implements  ActionListener {
    
    @Override
    public void actionPerformed(ActionEvent e) {
      System.out.println("버튼을 클릭하였습니다. "
                + "o(>.<)o 꺄~~~");
      // 안쪽클래스에서는 바깥클래스의 자원을  내 것처럼 사용가능
      dispose();
    }
  }
  //////////////// inner class 끝 ////////////////////
  
  public static void main(String[] args) {
    new EventHandlingInnerClass();
  }
}
```

![08](/md/legacy-assets/java/21/08.webp)

---

### Anonymous inner class

* **이벤트 처리 코드의 재사용성이 낮은 방법**

1. Window Component를 상속
2. Component를 선언
3. 생성
4. 이벤트 등록

```java
// 1. Window Component를 상속
public class Test extends Frame { ... }

// 2. Component를 선언
Button btn;

// 3. 생성
public Test() {
    btn = new Button();
}

// 4. 이벤트 등록
// anonymous inner class
btn.addActionListener(new ActionListener() {
    
  @Override
  public void actionPerformed(ActionEvent e) {
    // 이벤트가 발생했을 때 처리할 코드
  }
});
```

```java
// anonymous inner class로 이벤트 처리
// 1. 윈도우 컴포넌트 상속
public class EventHandlingAnonymous extends Frame {
  // 2. 이벤트처리에 사용할 Component 선언
  private Button btn;
  
  public EventHandlingAnonymous() {
    super("click!");
    
    // 3. 컴포넌트 생성
    btn = new Button("버튼");
    
    // 4. 배치
    Panel panel = new Panel();
    panel.add(btn);
    add("Center",panel);
    
    // 5. 이벤트 등록 : anonymous inner class
    btn.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e)  {
        System.out.println("버튼 클릭!");
      }
    });
    
    // 6. 윈도우 크기 설정
    setBounds(200, 100, 400, 200);
    // 7. 가시화
    setVisible(true);
  }
  public Button getBtn() {
    return btn;
  }
  public static void main(String[] args) {
    new EventHandlingAnonymous();
  }
}
```

![09](/md/legacy-assets/java/21/09.webp)

---

### OOOAdapter class가 사용되어야 하는 이유

* OOOListener interface를 구현한 class는 **사용하지 않는 method일지라도 모두 Override 해야한다.**

```java
// OOOAdapter class가 사용되어야 하는 이유
@SuppressWarnings("serial")
public class UseWindowEvent extends Frame implements  WindowListener {
  public UseWindowEvent() {
    super("윈도우 이벤트 연습");
    
    setBounds(100, 100, 400, 400);
    setVisible(true);

    addWindowListener(this);
  }
  
  public static void main(String[] args) {
    new UseWindowEvent();
  }

  // WindowListener interface를 구현한 class는
  // 사용하지 않는 method일지라도 모두 Override  해야한다.
  @Override
  public void windowOpened(WindowEvent e) {
    System.out.println("windowOpened");
  }
  @Override
  public void windowClosing(WindowEvent e) {
    System.out.println("windowClosing");
    dispose();
  }
  @Override
  public void windowClosed(WindowEvent e) {
    // windowClosing에서 dispose()가 호출되면 그때  windowClosed가 호출
    System.out.println("windowClosed");
  }
  @Override
  public void windowIconified(WindowEvent e) {
    System.out.println("windowIconified");
  }
  @Override
  public void windowDeiconified(WindowEvent e) {
    System.out.println("windowDeiconified");
  }
  @Override
  public void windowActivated(WindowEvent e) {
    System.out.println("windowActivated");
  }
  @Override
  public void windowDeactivated(WindowEvent e) {
    System.out.println("windowDeactivated");
  }
}
```

### Adapter class

* **이벤트를 처리하는 interface가 추상 method를 하나 이상 가지고 있을 때 interface를 미리 구현한 class들**
  * class의 내용들은 empty
  * **사용상의 편의성이 증대**

```java
@SuppressWarnings("serial")
public class UseWindowAdapter extends Frame {
  public UseWindowAdapter() {
    super("윈도우 이벤트 연습");
    
    setBounds(100, 100, 400, 400);
    setVisible(true);

    UseWindowAdapter.WindowImpl wi = this.new  WindowImpl();
    addWindowListener(wi);
  }
  
  public static void main(String[] args) {
    new UseWindowAdapter();
  }

  // WindowAdapter class를 상속받으면 필요한 method만  Override하면 된다.
  public class WindowImpl extends WindowAdapter {
    
    @Override
    public void windowClosing(WindowEvent e) {
        dispose();
    }
  }
}
```

![10](/md/legacy-assets/java/21/10.webp)

---

### 이벤트처리 구현 예시(01)

![11](/md/legacy-assets/java/21/11.webp)

* **입력버튼이 클릭되면 TextField의 입력값을 가져와서 TextArea에 추가할 것**
* "입력" 버튼클릭 -> **ActionEvent**
  * **ActionListener**, 등록은 **addActionListener(처리될 곳)**
* TF에서 값 가져오는건 TextComponent 클래스의 **getText** 사용
* TA에 TextArea의 **append**를 사용해서 가져온 text를 추가
* **Is-A 구현시**

![12](/md/legacy-assets/java/21/12.webp)

```java
// ActionListener를 사용한 이벤트 처리
// is-a 관계로 이벤트를 처리
@SuppressWarnings("serial")
public class UseActionListener extends Frame implements ActionListener {

  // 다른 메소드에서 사용해야 하므로 지역변수에서 인스턴스변수로 옮김
  private TextField tfName;
  private TextArea taDisplay;
  
  public UseActionListener() {

    super("ActionEvent 사용");
    
    Label lblName = new Label("이름");
    Button btnAdd = new Button("추가");
    Button btnClose = new Button("종료");
    Panel panelNorth = new Panel();
    tfName = new TextField(20);
    taDisplay = new TextArea();
    
    panelNorth.add(lblName);
    panelNorth.add(tfName);
    panelNorth.add(btnAdd);
    panelNorth.add(btnClose);
    setLayout(new BorderLayout());
    add(BorderLayout.NORTH, panelNorth);
    add(BorderLayout.CENTER, taDisplay);
    
    // 이벤트 등록
    btnAdd.addActionListener(this); // 버튼에서 이벤트 등록(클릭)
    tfName.addActionListener(this); //  텍스트필드에서 이벤트 등록(엔터)
    btnClose.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        dispose();
      }
    });
    
    setBounds(200, 150, 400, 250);
    setVisible(true);
    addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        dispose();
      }
    });
  }
  
  public static void main(String[] args) {
    new UseActionListener();
  }
  
  @Override
  public void actionPerformed(ActionEvent e) {
    // TextField의 값을 받아와서, TextArea에 추가
    String name = tfName.getText();
    if (!name.isEmpty()) {  // 입력문자열이 비어있지 않다면
      taDisplay.append(name+"\n");
      
      // TextField의 값을 초기화
      tfName.setText("");
    }
    // 커서를 TextField에 재설정
    tfName.requestFocus();
  }
}
```

![13](/md/legacy-assets/java/21/13.webp)

---

### 이벤트처리 구현 예시(02)

![14](/md/legacy-assets/java/21/14.webp)

* **List 아이템을 클릭하면 라벨에 해당 아이템의 정보를 표시할 것**
* **ItemEvent** 처리
  * **ItemListener 인터페이스 사용**
  * **리스트컴포넌트.addItemListener** 사용
	* 리스트 클릭 했을 때 **getSelectedItem()**로 선택한 item 받기
	* 리스트를 선택했을 때 선택한 리스트의 인덱스를 얻는 **getSelectedIndex()**도 존재 
		* **getItem(int index)**랑 같이 사용가능
* **Is-A 구현시**

![15](/md/legacy-assets/java/21/15.webp)

```java
/**
* ItemEvent를 처리하는 ItemListener의 사용
*/
@SuppressWarnings("serial")
public class UseItemListener extends Frame implements ItemListener {

  private List list;
  private Label lbl;

  public UseItemListener() {
    
    list = new List();
    list.add("이재찬/27");
    list.add("정택성/26");
    list.add("공선의/27");
    lbl = new Label("이름 :                           나이 : ");
    
    add(BorderLayout.CENTER, list);
    add(BorderLayout.SOUTH, lbl);
    
    list.addItemListener(this);
    
    addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent e) {
        dispose();
      }
    });
    
    setBounds(300, 200, 300, 300);
    setVisible(true);
  }
  public static void main(String[] args) {
    new UseItemListener();
  }

  @Override
  public void itemStateChanged(ItemEvent e) {
    // 리스트의 아이템이 선택되면 선택한 아이템을 가져와서
    // 라벨의 값 변경
    String[] nameAndAge = list.getSelectedItem().split("/");
    String name = nameAndAge[0];
    String age = nameAndAge[1];
    // 긴 문자열이기 때문에 StringBuilder로 처리
    StringBuilder viewData = new StringBuilder();
    viewData.append("이름 : ").append(name).append("              나이 : ").append(age);
    lbl.setText(viewData.toString());
  }
}
```

![16](/md/legacy-assets/java/21/16.webp)

---

### 숙제풀이

![17](/md/legacy-assets/java/21/17.webp)

* [Is-A 관계로 구현](https://github.com/younggeun0/SSangYoung/blob/master/dev/workspace/sistJavaStudy/src/date181211/ChangeFontColor.java)

* Has-A 관계로 구현
  * [Design](https://github.com/younggeun0/SSangYoung/blob/master/dev/workspace/sistJavaStudy/src/date181211/CFCDesign.java)
  * [Event Handler](https://github.com/younggeun0/SSangYoung/blob/master/dev/workspace/sistJavaStudy/src/date181211/CFCEventHandler.java)

![18](/md/legacy-assets/java/21/18.webp)
