즐겁게!! 자신있게!! 살아보세!!

재밌는 인생을 위하여! 영촤!

Language_Study/JAVA

[JAVA, App] 16.이벤트처리

Godwony 2020. 12. 27. 12:02
728x90
반응형

Event 처리

  • Event는 외부에서 발생하는 사건
  • 자바의 awt 나 swing의 이벤트 처리는 Listener 인터페이스나 Adapter 클래스가 처리합니다.

1.이벤트 처리 방법

  • 처리하고자 하는 이벤트의 Listener 인터페이스를 implements 하거나 Adapter 클래스를 상속받은 클래스의 인스턴스를 생성

  • 컴포넌트.add이벤트리스너(앞에서 생성한 인스턴스);

  • 이러한 방식의 처리를 Delegate(위임) 를 처리 방식

    • 이벤트가 발생한 객체가 이벤트를 처리하는 것이 아니고 이벤트가 발생한 객체가 다른 객체에게 이벤트 처리를 위임하는 방식
    • 컴포넌트는 출력에만 집중하고 다른 작업은 별도의 객체가 처리하는 것이 유지보수에 유리
  • 이벤트 처리하는 메소드를 확인

    • 이 메소드의 매개변수를 이용하면 이벤트가 발생한 객체에 대한 정보를 가져올 수 있습니다.
    • 자바에서는 getSource()를 호출하면 이벤트가 발생한 객체에 대한 참조를 리턴받을 수 있습니다.
    • 가지고 있는 메소드들이 이벤트별로 다른데 이 메소드들이 이벤트에서 사용할 정보를 리턴해줍니다.

2.이벤트 처리 실습

  • 버튼을 누르거나 메뉴를 누르는 경우 또는 TextField에서 Return 키를 누르는 경우를 처리할 때는 ActionListener를 이용해서 처리
  • 버튼과 텍스트 필드를 만들고 버튼을 누르면 텍스트 필드에 입력된 내용을 콘솔에 출력

1) Anonymous 클래스를 이용하는 방법

  • Frame으로 부터 상속받는 클래스
public class MyWindow extends Frame {
    private Button btn;
    private TextField tf;

    public MyWindow() {
        //여러 개의 컴포넌트를 묶어줄 Container 생성
        Panel p = new Panel();

        //컴포넌트들을 생성
        btn = new Button("클릭");
        tf = new TextField(30);

        //버튼의 이벤트 처리를 위한 ActionListener 인터페이스의 anonymous class 생성
        ActionListener listener = 
                new ActionListener() {
                    //버튼을 누르거나 텍스트 필드에서 Return 누르거나 메뉴를 누르면 호출되는 메소드
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        //입력한 내용 가져오기
                        String msg = tf.getText();
                        //출력
                        System.out.println(msg);

                    }
        };

        //btn 에서 Action 이벤트가 발생하면 listener가 대신 처리하도록 위임(Delegation)
        btn.addActionListener(listener);

        //컴포넌트들을 컨테이너에 배치
        p.add(tf);
        p.add(btn);

        //컨테이너를 윈도우에 배치
        add(p);

        //Frame 기본 설정
        setTitle("이벤트 처리");
        setLocation(100,100);
        setSize(200,200);
        setVisible(true);
    }
}
  • 별도의 이벤트 처리 클래스를 생성해서 이벤트를 처리
    • ActionListener 인터페이스를 implements 한 클래스를 생성 - EventHandler
public class EventHandler implements ActionListener {
    private TextField tf;

    //생성자 : TextField 1개를 주입받는 생성자
    public EventHandler(TextField tf) {
        this.tf = tf;
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        String msg = tf.getText();
        System.out.println(msg);

    }

}
  • MyWindow 클래스의 생성자에서 이벤트 연결
//이벤트 처리를 위한 인스턴스를 생성
EventHandler handler = new EventHandler(tf);
btn.addActionListener(handler);

3.인터페이스를 이용하는 방법

1) 인터페이스를 구현한 클래스를 만들고 인스턴스를 만드는 방법

  • 유지보수를 위해서는 이 방식을 권장
  • 생성자나 setter 메소드를 이용해서 데이터를 넘겨야 하는 어려움이 있음

2) 인터페이스를 가지고 Anonymous Class를 만드는 방법

  • 일반적인 자바(안드로이드) 책에서 많이 사용하는 방법
  • 이 방법은 컴포넌트가 구현된 클래스에 만들기 때문에 클래스의 변수 사용이 자유로워서 많이 이용

3) 특수한 인터페이스의 경우는 람다를 이용하는 방법

  • Android Studio 는 이 방식으로 최적화

4.Event Routing

  • 여러 개의 이벤트를 하나의 인스턴스가 처리하도록 하는 방법

  • 1개의 이벤트를 1개의 인스턴스가 처리하도록 하면 여러 개의 이벤트를 처리할 때 인스턴스의 개수가 늘어나고 제어하기가 어려워집니다.

  • 이 때는 이벤트 처리 메소드에서 이벤트가 발생한 인스턴스를 구분해서 분기를 해야 합니다.

    • awt 나 swing에서는 이벤트 처리 메소드의 매개변수가 getSource()를 호출하면 이벤트가 발생한 객체의 참조를 리턴하기 때문에 이를 이용해서 구분할 수 있고 ActionEvent의 경우는 getActionCommand()를 호출하면 문자열을 리턴해주는데 이 문자열이 버튼의 텍스트입니다.
    • getSource()를 사용하는 경우는 배열이나 List 인 경우
  • 이전 Frame에 버튼을 2개 추가해서 이벤트 라우팅 구현 - MyWindow 클래스에서 작업
    1) 인스턴스 변수로 버튼을 2개를 추가

private Button btn1, btn2;

2)생성자 메소드에서 버튼 2개를 만들어서 윈도우에 추가
//버튼을 생성해서 패널에 추가
        btn1 = new Button("버튼1");
        p.add(btn1);

        btn2 = new Button("버튼2");
        p.add(btn2);

        //버튼의 이벤트 처리 - 라우팅을 이용하지 않는 경우
        /*
        ActionListener event1 = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("버튼1을 클릭했습니다.");

            }
        };
        btn1.addActionListener(event1);

        ActionListener event2 = new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("버튼2를 클릭했습니다.");

            }
        };
        btn2.addActionListener(event2);
        */

        //이벤트 라우팅을 이용하는 방법
        ActionListener eventRouting = 
            new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                System.out.println(arg0.getActionCommand() + " 예약");

            }
        };

        btn1.addActionListener(eventRouting);
        btn2.addActionListener(eventRouting);
  • p를 만들고 난 후에 코드를 추가해야 합니다.

5.ItemEvent

  • 체크박스 나 라디오 버튼 이나 콤보박스(Choice)의 선택을 변경하는 경우에 발생하는 이벤트
  • ItemListener 인터페이스가 처리
  • 이벤트 처리 메소드의 매개변수가 getItem()을 호출하면 어떤 Item에 이벤트가 발생했는지 알 수 있고 getStateChange() 메소드를 호출하면 어떤 상태로 변경되었는지 확인이 가능

6.TextListener

  • TextField 나 TextArea에서 텍스트의 변경이 발생했을 때를 처리하는 리스너

  • textValueChanged(TextEvent e) 메소드를 이용해서 처리

  • 텍스트가 변경될 때 상태 변화에 따라 메시지를 출력하거나 유효성을 검사하는 용도로 사용

  • 영문 대소문자 그리고 숫자 및 특수문자가 1개 이상이면 강함이라고 출력

  • 그렇지 않은 경우에는 약함이라고 출력

  • 특수문자는 영문 대소문자가 아니고 숫자도 아니면 특수문자로 판단

//텍스트 필드나 텍스트 에어리어의 문자열이 변경될 때 처리를 위한 인스턴스
        TextListener tl = new TextListener() {
            @Override
            public void textValueChanged(TextEvent arg0) {
                //텍스트 필드에 입력된 문자열을 가져오기
                String msg = tf.getText();
                //대소문자 숫자, 특수문자 개수를 저장할 변수를 생성
                int dae = 0;
                int so = 0;
                int su = 0;
                int etc = 0;

                //문자열을 문자단위로 접근
                for(int i=0; i<msg.length(); i=i+1) {
                    //앞에서부터 한글자씩 가져오기
                    char ch = msg.charAt(i);
                    if(ch >= 'A' && ch <= 'Z') {
                        dae = dae + 1;
                    }else if(ch >= 'a' && ch <= 'z') {
                        so = so + 1;
                    }else if(ch >= '0' && ch <= '9') {
                        su = su + 1;
                    }else {
                        etc = etc + 1;
                    }
                }

                if(dae*so*su*etc != 0 ) {
                    System.out.println("강함");
                }else {
                    System.out.println("약함");
                }

            }
        };
        tf.addTextListener(tl);

7.KeyListener

  • 키보드 이벤트를 처리하기 위한 리스너
    1) 처리를 위한 메소드
void keyPressed(KeyEvent e): 키보드를 누를 때

void keyReleased(KeyEvent e): 키보드에서 손을 뗄 때

void keyTypes(KeyEvent e): 키보드를 누르고 누른 키가 문자 키일 때 호출되는 메소드
keyPressed 는 키보드 위치 만을 감지를 해서 대소문자 구분을 하지 못했고 keyTypes가 대소문자 구분을 했습니다.

2) KeyEvent 클래스

  • 모든 key 값이 상수로 정의되어 있습니다.
  • getKeyChar()를 이용해서 누른 문자를 가져올 수 있고 getKeyCode()를 이용해서 누른 키보드의 숫자 값을 가져올 수 있습니다.

3) 방향키를 이용해서 레이블을 움직이고 control + x를 누르면 프로그램 종료하는 윈도우

public class KeyWindow extends Frame {

    private Label lbl;

    public KeyWindow() {
        //컴포넌트들의 위치 변경이나 크기 변경이 가능하도록 레이아웃을 null로 설정
        setLayout(null);

        //레이블을 생성하고 배치
        lbl = new Label("@");
        lbl.setLocation(20, 30);
        lbl.setSize(15,15);
        add(lbl);

        //레이블을 1초마다 아래로 5만큼씩 이동하는 스레드
        Thread th = new Thread() {
            public void run() {
                while(true) {
                    try {
                        Thread.sleep(1000);
                        int x = lbl.getLocation().x;
                        int y = lbl.getLocation().y;
                        y = y + 5;
                        lbl.setLocation(x, y);
                    }catch(Exception e) {}
                }
            }
        };
        th.start();

        //키보드 이벤트 처리를 위한 인스턴스를 생성
        KeyListener listener = new KeyListener() {
            //키보드를 눌렀을 때 호출되는 메소드
            @Override
            public void keyPressed(KeyEvent arg0) {
                //조합키 확인 : shift-1, control-2, alt-8
                int modifiers = arg0.getModifiers();
                //control + X 이면 종료
                //control 키가 눌러졌는지 확인
                if((modifiers & 2) != 0) {
                    //별도로 누른 키가 X 인지 확인 - 대소문자를 구분해서 하고자 하는 경우는 getKeyChar()
                    int key = arg0.getKeyCode();
                    if(key == KeyEvent.VK_X) {
                        System.exit(0);
                    }
                }

                //System.out.println("아무 키나 누르면 호출됩니다.");

                //keyChar는 대소문자 구분 : a -> a, A -> A
                //System.out.println(arg0.getKeyChar());

                //keyCode는 대소문자 구분 안함 : a->65 A->65
                //System.out.println(arg0.getKeyCode());

                //현재 레이블의 위치 가져오기
                int x = lbl.getLocation().x;
                int y = lbl.getLocation().y;

                //누른 키보드 값 가져오기
                int code = arg0.getKeyCode();

                switch(code) {
                case KeyEvent.VK_UP:
                    y = y - 5;
                    break;
                case KeyEvent.VK_DOWN:
                    y = y + 5;
                    break;
                case KeyEvent.VK_LEFT:
                    x = x - 5;
                    break;
                case KeyEvent.VK_RIGHT:
                    x = x + 5;
                    break;
                }
                lbl.setLocation(x, y);

            }
            //키보드에서 손을 뗄 때 호출되는 메소드
            @Override
            public void keyReleased(KeyEvent arg0) {
                //System.out.println("키보드에서 손을 떼면 무조건 호출");
            }
            //문자키를 눌렀을 때 호출되는 메소드
            @Override
            public void keyTyped(KeyEvent arg0) {
                //System.out.println("문자 키를 눌렀을 때 호출");
            }
        };
        //윈도우에 키보드 이벤트 리스너를 연결
        this.addKeyListener(listener);

        setTitle("키보드 이벤트");
        setLocation(100,100);
        setSize(400,400);
        setVisible(true);
    }
}

8.MouseListener

  • 마우스 이벤트를 처리해주는 리스너
  • 클릭, 영역에 마우스가 들어온 경우, 영역에서 벗어나는 경우, 마우스는 누를 때, 마우스에서 손을 뗄 때 처리를 위한 메소드가 존재
  • MouseEvent 에서는 마우스의 좌표를 리턴해주는 메소드와 클릭 횟수 등을 리턴해주는 메소드가 존재

9.MouseMotionListener

  • 마우스를 드래그 할 때를 처리해주는 리스너
  • 버튼을 누르고 움직일 때는 위한 Dragged 메소드와 마우스를 움직이면 무조건 호출되는 Moved 메소드가 존재

10.WindowListener

  • 윈도우 이벤트를 처리해주는 리스너

  • 윈도우 관련된 7개의 이벤트 처리 메소드가 존재

  • 윈도우의 종료 버튼을 누를 때 처리를 위한 메소드는 windowClosing

  • 이전 윈도우의 생성자에 종료 버튼을 누를 때 프로그램이 종료되도록 이벤트 처리 코드를 추가

        WindowListener windowListener = new WindowListener() {

            @Override
            public void windowActivated(WindowEvent arg0) {
            }

            @Override
            public void windowClosed(WindowEvent arg0) {
            }

            //종료 버튼을 누를 때 호출되는 메소드
            @Override
            public void windowClosing(WindowEvent arg0) {
                //프로그램 종료
                System.exit(0);
            }

            @Override
            public void windowDeactivated(WindowEvent arg0) {
            }

            @Override
            public void windowDeiconified(WindowEvent arg0) {
            }

            @Override
            public void windowIconified(WindowEvent arg0) {
            }

            @Override
            public void windowOpened(WindowEvent arg0) {
            }
        };
        //윈도우 이벤트 연결
        this.addWindowListener(windowListener);

11.이벤트 처리를 Listener 인터페이스를 이용해서 처리하도록 하면 실제 사용하는 메소드는 1개 밖에 없는 인터페이스의 메소드는 전부 추상 메소드라서 반드시 재정의 해야 합니다.

  • java 의 awt에서는 메소드가 2개 이상인 Listener 들을 Adapter 클래스에 비어있는 내용으로 구현해서 필요한 메소드만 재정의 할 수 있도록 Adapter class를 제공합니다.

  • Adapter class는 전부 추상 클래스라서 직접 인스턴스를 생성하지 못합니다.

  • 앞의 윈도우 이벤트 처리 구문을 수정

//Listener는 인터페이스라서 모든 메소드를 구현해야 하지만
        //Adapter는 추상클래스라서 추상메소드 와 필요한 메소드만 구현하면 됩니다.
        WindowAdapter windowListener = new WindowAdapter() {
            //종료 버튼을 누를 때 호출되는 메소드
            @Override
            public void windowClosing(WindowEvent arg0) {
                //프로그램 종료
                System.exit(0);
            }
        };
        //윈도우 이벤트 연결
        this.addWindowListener(windowListener);
728x90
반응형

'Language_Study > JAVA' 카테고리의 다른 글

[JAVA, App] 18.Stream  (0) 2020.12.27
[JAVA, App] 17.자바GUI  (0) 2020.12.27
[JAVA, App] 15.MutualExclusion  (0) 2020.12.27
[JAVA, App] 14.기본API클래스  (0) 2020.12.27
[JAVA, App] 13.Framework  (0) 2020.12.25