CHAPTER 10 자바의 이벤트 처리
10.1 이벤트 기반 프로그래밍(Event Driven Programming)
10.2 이벤트 객체
10.3 이벤트 리스너
10.4 어댑터(Adapter) 클래스
10.5 KeyEvent와 KeyListener
10.6 MouseEvent와 MouseListener, MouseMotionListener, MouseWheelListener
<그림으로 흐름 파악하기>




interface ActionListener { //포함된 메소드를 개발자가 상속 받아서 구현해야 한다.
//Action 이벤트 발생시 자동 호출됨
public void actionPerformed(ActionEvent e);
}interface MouserListener { //아래의 5개 메소드 모두 개발자가 구현해야 함
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); //마우사가 컴포넌트 위애서 내려오는 순간 호출
}
//이벤트 소스가 여러개라면, 여러개의 객체를 생성해야하는데? 다음과 같이 인터페이스로 구현한다.
//이미 다 지정이 다 되어있어서 해당 인터페이스에 맞는 메소드가 각 순간에 호출된다.Component.addXXXListener(listener)JButton.addActionListener(); //Action 리스너
JButton.addKeyListener(); //Key 리스너
JButton.addFocusListener(); //Focus 리스너JButton.addActionListener(new MyButtonListener1());
JButton.addActionListener(new MyButtonListener2());
JButton.addActionListener(new MyButtonListener3());
//이때, 리스너는 등록된 반대 순으로 모두 실행된다.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class IndepClassListener extends JFrame {
public IndepClassListener(){ //초기값 정보 설정
setTitle("Action 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane(); //기본적인 컨텐트 팬 설정(<- 컴포넌트를 등록하기 위해)
c.setLayout(new FlowLayout()); //레이아웃 설정
JButton btn = new JButton("Action"); //버튼 관리
btn.addActionListener(new MyActionListener()); //Action 이벤트 리스너 달기
//-> 각 컴포넌트가 가지고 있는 전용 이벤트를 처리히해줄 리스너(메소드)를 안내
//->
c.add(btn); //컨텐트 팬에 버튼을 등록 시킴
setSize(350, 150); //화면을 조정하여 처음 보여줌
setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new IndepClassListener();
}
}
//독립된 클래스로 이벤트 리스너()를 작성한다.
class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) { //버튼에 클릭이 발생했다라고 하는 정보(발생시간, 좌표 등등..) 가 e 에게 제공됨
JButton b = (JButton)e.getSource(); //이벤트 소스 버튼 알아내기(이벤트가 어디서 발생한 버튼 인지를 알아오고 그것에 b로 접근)
if(b.getText().equals("Action")) //버튼의 문자열이 영문 "Action" 인지 비교
b.setText("액션"); // 버튼의 문자열을 "액션"으로 변경
else
b.setText("Action"); //버튼의 문자열을 "Action" 으로 변경
}
}


import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class InnerClassListener extends JFrame {
InnerClassListener() {
setTitle("Action 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
JButton btn = new JButton("Action");
btn.addActionListener(new MyActionListener());
c.add(btn);
setSize(350, 150);
setVisible(true);
}
//Action 이벤트 리스너를 내부 클래스로 작성
//private 으로 선언하여 InnerClassListener 외부에서 사용할 수 없게 함
private class MyActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
JButton b = (JButton)e.getSource(); //이벤트가 발생했을 때 버튼에 대한 접근 참조변수 b 로
if(b.getText().equals("Action")) //버튼의 문자열이 "Action" 인지 비교
b.setText("액션"); // 버튼의 문자열을 "액션"으로 변경
else
b.setText("Action"); //버튼의 문자열을 "Action" 으로 변경
//이 코드가 하나 더 추가됨
//InnerClassListener 의 멤버나 JFrame 의 멤버를 호출할 수 있음
//프레임 타이틀에 버튼 문자열을 출력한다.
InnerClassListener.this.setTitle(b.getText());
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new InnerClassListener();
}
}



new 익명클래스의수퍼클래스이름(생성자의 인자들) ㅖ
----
클래스 정의
----
}
컨텐트팬의 아무 위치에 마우스 버튼을 누르면 마우스 포인트가 있는 위치로 "hello" 문자열을 옮기는 스윙 응용프로그램을 작성하라.
응용프로그램에 마우스 클릭이라는 이벤트가 발생을 처리해주는 코드 추가
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class MouseListenerEx extends JFrame {
private JLabel la = new JLabel("Hello"); /생성자와 내부 클래스 외부에 레이블을 미리 만들어놓음
public MouseListenerEx() {
setTitle("Mouse 이벤트 리스너 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane(); //지금 응용프로그램의 기본적인 패널 정보를 불러오기 - 그래야 부착이 가능하니까
c.addMouseListener(new MyMouseListener());
// -> 내 컨텐츠 팬에 마우스가 눌러졌을때의 그 이벤트를 어떻게 처리할지 제공
// 미리 5가지 정보를 정의 부분에 제공됨
// 나는 눌러졌을 떄의 정보만 제공해줄 것이기 때문에
// 일단 다 호출하고 그 중 mousePressed 호출
c.setLayout(null); //레이아웃을 아무것도 쓰지 않기
la.setSize(50, 20); //헬로 문자열의 위치
la.setLocation(30,30);
c.add(la); //패널에 부착시켜서 눈에 보이도록 하기
setSize(250, 250); //윈도우의 크기 값
setVisible(true);
}
//마우스 버튼이 눌러진 위치를 알아내어 la("Hello" 문자열)를 그 위치로 옮긴다.
class MyMouseListener implements MouseListener {
public void mousePressed(MouseEvent e) { //이벤트를 e 로 받고
int x = e.getX(); //객체의 x,y 정보를 얻어와서 x,y 에 보관
int y = e.getY();
la.setLocation(x,y); // 그 위치로 레이블을 이동시키기
}
//호출이 되서 수행되는 정의 코드는 제공
public void mouseReleased(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new MouseListenerEx();
}
}




패스
눌렀다, 떨어졌다, 떼는순간 유니코드인 경우 이렇게 3가지의 키 이벤트 발생
키 입력은 화면상의 변화가 아니기 때문에 포커스를 받아야지만 키 입력이 가능
키 입력을 가지고 포커를 가진 컴포넌트가 그걸 받아서 무언가 할수 있다.
컨텐츠 팬에 포커스를 강제로 지정해서 그 정보를 활용해서 타입핑한것이 반영하도록 다음 코드가 반드시 필요

가상키를 활용해서 유니코드값이 없는 키 문제 해결

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class KeyListenerEx extends JFrame {
private JLabel [] keyMessage; //3개의 메세지를 출력할 레이블 컴포넌트 배열
public KeyListenerEx() {
setTitle("KeyListener 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
c.addKeyListener(new MyKeyListener());
// 레이블 배열을 3개 생성하고 각 레이블 컴포넌트 생성
keyMessage = new JLabel[3]; //레이블 배열 생성
keyMessage[0] = new JLabel("getKeyCode() ");
keyMessage[1] = new JLabel("getKeyChar() ");
keyMessage[2] = new JLabel("getKeyText() ");
// 3개의 레이블 컴포넌트를 컨텐츠 팬에 부착
for(int i = 0; i<keyMessage.length; i++) {
c.add(keyMessage[i]);
// 배경색이 보이도록 불투명 속성 강제 설정
keyMessage[i].setOpaque(true);
// 배경색 CYAN 색으로 변경
keyMessage[i].setBackground(Color.YELLOW);
}
setSize(300, 150);
setVisible(true);
// 컨텐츠 팬이 키 입력을 받을 수 있도록 포커스 강제 지정 (꼭 필요한 코드)
c.setFocusable(true);
c.requestFocus();
}
//key 리스너 구현
class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode(); //지금 눌러진 키 코드 알아내기
char keyChar = e.getKeyChar(); //지금 눌러진 키 문자 값 알아내기
//키 코드 출력
keyMessage[0].setText(Integer.toString(keyCode));
//키 문자 출력 -> 유니코드가 없으면 그냥 사각형이 나온다.
keyMessage[1].setText(Character.toString(keyChar));
//키 이름 문자열 출력
keyMessage[2].setText(KeyEvent.getKeyText(keyCode));
System.out.println("KeyPressed"); //콘솔 : keyPressed 출력
}
public void keyReleased(KeyEvent e) {
System.out.println("KeyReleased"); //콘솔 : keyReleased 출력
}
public void keyTyped(KeyEvent e) {
System.out.println("KeyTyped"); //콘솔 : keyTyped 출력
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new KeyListenerEx();
}
}

유니코드가 있는 경우

유니코드가 없는 경우

<F1> 키를 입력받으면 컨텐트팬의 배경을 초록색으로, % 키를 입력받으면 노란색으로 변경import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class KeyCodeEx extends JFrame { // 빈 레이블 컴포넌트 생성
private JLabel la = new JLabel();
public KeyCodeEx() {
setTitle("Key Code 예제 : F1키:초록색, % 키 노란색");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.addKeyListener( new MyKeyListener( ) );
c.add(la);
setSize(300,150);
setVisible(true);
// 컨텐트팬이 키 입력을 받을 수 있도록 포커스 강제 지정
c.setFocusable(true);
c.requestFocus();
}
//Key 리스너 구현
class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
Container contentPane = (Container)e.getSource();
//la에 입력된 키의 키 이름 문자열을 출력하여 사용자에게 보고함
la.setText(KeyEvent.getKeyText(e.getKeyCode())+"키가 입력되었음");
if(e.getKeyChar() == '%') // 입력된 키가 % 인 경우
contentPane.setBackground(Color.YELLOW);
else if(e.getKeyCode() == KeyEvent.VK_F1) // <F1> 확인
contentPane.setBackground(Color.GREEN);
}
}
public static void main(String [] args) {
new KeyCodeEx();
}
}
shift + 5 -> 노란색
f1 -> 초록색

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class FlyingTextEx extends JFrame {
private final int FLYING_UINT = 10; //10픽셀 단위 이동
private JLabel la = new JLabel("HELLO"); //레이블 컴포넌트
public FlyingTextEx() {
setTitle("상, 하, 좌, 우 키를 이용하여 텍스트 움직이기");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(null); //컨텐트팬의 배치관리자 삭제
//컨텐트팬에 key 리스너 달기
c.addKeyListener(new MyKeyListener()); //키보드와 관련한 일은 MyKeyListener 에게 일을 시킴
la.setLocation(50,50); //la 초기 위치는 (50,50)
la.setSize(100,20);
c.add(la);
setSize(300,300);
setVisible(true);
c.setFocusable(true); //컨텐트팬이 키 입력을 받을 수 있도록 포커스 강제 지정
c.requestFocus(); //컨텐트팬에 포커스를 잏은 경우 마우스를
// 클릭하면 다시 포커스를 얻게 함
//익명 클래스로 작성
c.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
//마우스가 클릭된 컴포넌트
Component c =(Component)e.getSource();
//혹시 모르니까 이코드를 하나 더 추가해줌.
c.setFocusable(true);
c.requestFocus(); //컴포넌트에게 포커스 설정
}
});
}
//key 리스너 구현
class MyKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
//입력된 키의 키코드를 알아낸다.
int keyCode = e.getKeyCode();
// 키 코드 값에 따라 상,하,좌,우 키를 판별하고
// la의 위치를 이동시킨다.
switch(keyCode) {
case KeyEvent.VK_UP: //위로 10픽셀 이동
la.setLocation(la.getX(), la.getY() - FLYING_UINT);
break;
case KeyEvent.VK_DOWN:
la.setLocation(la.getX(), la.getY() + FLYING_UINT);
break;
case KeyEvent.VK_LEFT:
la.setLocation(la.getX() - FLYING_UINT, la.getY());
break;
case KeyEvent.VK_RIGHT:
la.setLocation(la.getX() + FLYING_UINT, la.getY());
break;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new FlyingTextEx();
}
}


mousePressed(), mouseReleased(), mouseClicked()
//드래그는 한픽셀이 이동할떄마다 계속적으로 발생
mousePressed(), mouseDragged(), mouseDragged(), ..., mouseReleased()
//<-- MouseListener의 5개의 이벤트를 처리하는 경우 -->
mouseEntered(), mouseExited(), mousePressed(), mouseReleased()., mouseClicked()
//마우스 리스너 등록
component.addMouseListener(myMouseListener);
//<-- MouseMotionListener의 이벤트도 함께 처리하고자 하는 경우 -->
mouseDragged(), mouseMoved()
//마우스 모션 리스너 등록 필요
component.addMouseMotionListener(myMouseMotionListener);
//마우스 포인터의 위치
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
}
//입력된 마우스 버튼
public void mousePressed(MouseEvent e) {
if(e.getButton() == MouseEvent.BUTTON1)
System.out.println("Left Button Pressed");
}
//BUTTON1 -> 왼쪽 마우스 버튼
//BUTTON3 -> 오른쪽 마우스 버튼 (wheel 버튼이 있으면)
//BUTTON2 -> wheel 마우스 버튼
//마우스 클릭 횟수
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2) {
//더블 클릭을 처리하는 루틴
}
}
//팝업 메뉴 클릭
boolean isPopupTrigger();
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class MouseListenerAllEx extends JFrame {
//메세지 출력 레이블 컴포넌트
private JLabel la = new JLabel("No Mouse Event");
public MouseListenerAllEx() {
setTitle("MouseListener와 MouseMotionListener 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new FlowLayout());
//리스너 객체 생성
MyMouseListener listener = new MyMouseListener();
//MouseListener 리스너 등록
c.addMouseListener(listener);
//MouseMotionListener 리스너 등록
c.addMouseMotionListener(listener);
c.add(la);
setSize(300, 200);
setVisible(true);
}
//Mouse 리스너와 MouseMotion 리스너를 모두 가진 리스너 작성
class MyMouseListener implements MouseListener, MouseMotionListener {
// MouseListener 의 5개 메소드 구현
public void mousePressed(MouseEvent e) {
la.setText("MousePressed (" + e.getX()+ ","+ e.getY() + ")");
} //마우스가 눌러진 위치 (x,y) 점을 출력
public void mouseReleased(MouseEvent e) {
la.setText("MouseReleased (" + e.getX()+ ","+ e.getY() + ")");
} //마우스가 뗴어진 위치 (x,y) 점을 출력
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) { //마우스가 올라간
Component c = (Component)e.getSource(); //컴포넌트를 알아낸다.
c.setBackground(Color.CYAN);
}
public void mouseExited(MouseEvent e) { //마우스가 내려간
Component c = (Component)e.getSource(); //컴포넌트를 알아낸다.
c.setBackground(Color.YELLOW);
}
// MouseMotionListener 의 2개 메소드 구현
public void mouseDragged(MouseEvent e) {
la.setText("MouseDragged (" + e.getX()+ ","+ e.getY() + ")");
} //마우스가 드래깅되는 동안 계속 호출
public void mouseMoved(MouseEvent e) {
la.setText("MouseMoved (" + e.getX()+ "," +e.getY() + ")");
} //마우스가 움직이는 동안 계속 호출
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new MouseListenerAllEx();
}
}



import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class ClickAndDoubleClickEx extends JFrame {
public ClickAndDoubleClickEx() {
setTitle("Click and DoubleClick 예제");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
c.addMouseListener(new MyMouseListener()); //Mouse 리스너 달기
setSize(300, 200);
setVisible(true);
}
// MouseAdapter 를 상속받아 Mouse 리스너 구현
class MyMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2) { //더블 클릭의 경우
//[0,255] 사이의 랜덤한 r,g,b 정수 값 얻기
int r = (int)(Math.random()*256);
int g = (int)(Math.random()*256);
int b = (int)(Math.random()*256);
Component c = (Component)e.getSource(); //클릭한 컴포넌트를 알아낸다.
c.setBackground(new Color(r,g,b)); //컴포넌트의 배경을 r,g,b 색으로 칠한다.
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new ClickAndDoubleClickEx();
}
}

component.addMouseWheelListener(new MouseWheelListener)) {
public void mouseWheelMoved(MouseWheelEvent e) {
//마우스 휠의 구르는 방향에 따라 이벤트를 처리한다.
}
}