• Home
  • About
    • Young's Github Pages photo

      一日不作一日不食

    • About
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

Java 정리 21

11 Dec 2018

Reading time ~9 minutes

Java 정리 21 - AWT Event Handling


Event Handling

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

01


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

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

02

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

/**
* 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


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

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

05

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

/**
* 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();
  }
}
/**
* 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


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

  • 디자인에 해당하는 이벤트처리 코드가 매우 적거나 특정디자인에 해당하는 이벤트만 처리할 때
    • 디자인 클래스안에서 여러 이너 클래스로 이벤트를 구분하여 처리가능
  1. 윈도우 컴포넌트를 상속
  2. 이벤트 처리와 관계된 컴포넌트 선언
  3. 생성
  4. 이벤트를 처리하기 위한 inner class를 작성
  5. 추상 메소드 Override
  6. 이벤트 등록
// 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);
/**
* 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


Anonymous inner class

  • 이벤트 처리 코드의 재사용성이 낮은 방법
  1. Window Component를 상속
  2. Component를 선언
  3. 생성
  4. 이벤트 등록
// 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) {
    // 이벤트가 발생했을 때 처리할 코드
  }
});
// 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


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

  • OOOListener interface를 구현한 class는 사용하지 않는 method일지라도 모두 Override 해야한다.
// 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
    • 사용상의 편의성이 증대
@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


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

11

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

12

// 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


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

14

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

15

/**
* 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


숙제풀이

17

  • Is-A 관계로 구현

  • Has-A 관계로 구현

    • Design
    • Event Handler

18



Java