본문 바로가기
Programming/Java프로그래밍및실습

[자프실] 9. 자바의 이벤트 처리

by Lizardee 2024. 1. 11.
9.1 이벤트 기반 GUI 프로그래밍
이벤트 기반 프로그래밍
  • 이벤트 기반 프로그래밍(event driven programming): 이벤트 발생에 의해 프로그램 흐름이 결정되는 방식
  • 배치 실행(batch programming): 프로그램의 개발자가 프로그램의 흐름을 결정하는 방식

 

자바의 이벤트 기반 GUI 응용프로그램 구조

: 각 이벤트마다 처리하는 리스너 코드를 보유한다.

스윙 응용프로그램 이벤트의 실제 예

 

▶ 자바 스윙 프로그램에서 이벤트 처리 과정:

자바의 이벤트 기반 스윙 응용프로그램의 구조와 이벤트 처리 과정

  1. 이벤트 발생
  2. 이벤트 객체 생성: 현재 발생한 이벤트에 대한 정보를 가진 객체
  3. 응용프로그램에 작성된 이벤트 리스너 찾기
  4. 이벤트 리스너 실행
    - 리스너에 이벤트 객체 전달
    - 리스너 코드 실행

 


9.2 이벤트 객체
이벤트 객체와 이벤트 정보
  • 이벤트 객체: 발생한 이벤트에 관한 정보를 가진 객체

 

이벤트 객체와 이벤트 소스

이벤트 객체, 이벤트 소스, 이벤트가 발생하는 경우

 


9.3 사용자 이벤트 리스너 작성
리스너 인터페이스

리스너 인터페이스
자바에서 제공하는 리스너 인터페이스

 

이벤트 리스너 작성
  1. 이벤트와 이벤트 리스너 선택: 목적에 필요한 이벤트와 리스터 인터페이스 선택
    • 이벤트: Action 이벤트
    • 이벤트 리스너: ActionListener
    • 이벤트 객체: ActionEvent
  2. 이벤트 리스너 클래스 작성: 리스너 인터페이스를 상속받는 클래스를 작성하고, 추상 메소드 모두 구현
    • 독립 클래스로 작성
    • 내부 클래스(inner class)로 작성
    • 익명 클래스(anonymous class)로 작성
  3. 이벤트 리스너 등록: 이벤트를 받을 GUI 컴포넌트에 이벤트 리스너 등록

 

▶ 독립 클래스를 이용한 이벤트 리스너 작성

/*
 * 예제 9-1: 독립 클래스로 Action 이벤트 리스너 만들기
 * 버튼을 클릭할 때 발생하는 Action 이벤트를 처리할 MyActionListener 클래스를 독립 클래스로 작성하여,
 * 클릭할 때마다 버튼 문자열이 Action과 액션으로 번갈아 변하도록 한다.
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

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(250, 120);
		setVisible(true);
	}
	public static void main(String[] args) {
		new IndepClassListener();
	}
	
	// 독립된 클래스로 이벤트 리스너를 작성한다.
	class MyActionListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			JButton b = (JButton)e.getSource();  // 이벤트 소스 버튼 알아내기
			if(b.getText().equals("Action"))  // 버튼의 문자열이 Action인지 비교
				b.setText("액션");
			else
				b.setText("Action");  
		}
	}
}

 

▶ 내부 클래스를 이용한 이벤트 리스너 작성

/*
 * 예제 9-2: 내부 클래스로 Action 이벤트 리스너 만들기
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class InnerClassListener extends JFrame {
	public 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(200,120);
		setVisible(true);
	}
	
	// 내부 클래스로 Action 리스너를 작성한다.
	private class MyActionListener implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			JButton b = (JButton)e.getSource();
			if(b.getText().equals("Action"))
				b.setText("액션");
			else
				b.setText("Action");
			
			// InnerClassListener의 멤버나 JFrame의 멤버를 호출할 수 있음
			InnerClassListener.this.setTitle(b.getText());  // 프레임의 타이틀에 버튼 문자열을 출력한다.
		}
	}
	public static void main(String[] args) {
		new InnerClassListener();
	}
}

 

▶ 익명 클래스(anonymous class)로 이벤트 리스너 작성

/*
 * 예제 9-3: 익명 클래스를 이용하여 이벤트 리스너 작성
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class AnonymousClassListener extends JFrame {
	public AnonymousClassListener() {
		setTitle("Action 이벤트 리스너 작성");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Container c = getContentPane();
		c.setLayout(new FlowLayout());
		JButton btn = new JButton("Action");
		c.add(btn);
		
		btn.addActionListener(new ActionListener(){
			public void actionPerformed(ActionEvent e) {
				JButton b = (JButton)e.getSource();
				if(b.getText().equals("Action"))
					b.setText("액션");
				else
					b.setText("Action");
				
				// AnonymousClassListener의 멤버나 JFrame의 멤버를 호출할 수 있음
				setTitle(b.getText());
			}
		});
		setSize(200,120);
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new AnonymousClassListener();
	}
}

 

/*
 * 예제 9-4: 마우스 이벤트 리스너 작성 연습 - 마우스로 문자열 이동시키기
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseListenerEx extends JFrame {
	private JLabel la = new JLabel("Hello");  // Hello 문자열을 출력하기 위한 레이블
	
	public MouseListenerEx() {
		setTitle("Mouse 이벤트 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.addMouseListener(new MyMouseListener());  // 컨텐트팬에 이벤트 리스너 달기
		
		c.setLayout(null);  // 컨텐트팬의 배치관리자 삭제
		la.setSize(50, 20);  // 레이블의 크기 50x20 설정
		la.setLocation(30, 30);  // 레이블의 위치 (30,30)으로 설정
		c.add(la);  // 레이블 삽입
		
		setSize(200,200);
		setVisible(true);
	}
	
	// Mouse 리스너 구현
	class MyMouseListener implements MouseListener{
		public void mousePressed(MouseEvent e) {
			int x=e.getX();  // 마우스 클릭 좌표 x
			int y=e.getY();  // 마우스 클릭 좌표 y
			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) {
		new MouseListenerEx();
	}
}

 


9.4 어댑터(Adapter) 클래스

: 리스너의 모든 메소드를 단순 리턴하도록 만든 클래스

어댑터(Adapter) 클래스

 

/*
 * 예제 9-5: MouseAdapter를 상속받아 마우스 리스너 작성
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class MouseAdapterEx extends JFrame {
	private JLabel la = new JLabel("Hello");  // Hello 문자열을 출력하기 위한 레이블 컴포넌트
	
	public MouseAdapterEx() {
		setTitle("Mouse 이벤트 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.addMouseListener(new MyMouseAdapter());  // 컨텐트팬에 Mouse 이벤트 리스너 달기
		
		c.setLayout(null);  // 컨텐트팬의 배치관리자 삭제
		la.setSize(50,20);  // 레이블의 크기 50x20 설정
		la.setLocation(30,30);  // 레이블의 위치 (30,30)으로 설정
		c.add(la);  // 레이블 컴포넌트 삽입
		
		setSize(200,200); 
		setVisible(true);
	}
	
	// MouseAdapter를 상속받아 리스너 구현
	class MyMouseAdapter extends MouseAdapter{
		public void mousePressed(MouseEvent e) {
			int x=e.getX();  // 마우스 클릭 좌표 x
			int y=e.getY();  // 마우스 클릭 좌표 y
			la.setLocation(x,y);  // 레이블의 위치를 (x,y)로 이동
		}
	}
	
	public static void main(String[] args) {
		new MouseAdapterEx();
	}
}

 


9.5 Key 클래스와 KeyListener
Key 이벤트와 포커스
  • Key 이벤트: 사용자가 키를 입력할 때 발생하는 이벤트
  • 포커스(focus): 컴포넌트나 응용프로그램이 Key 이벤트를 독점하는 권한
    • 현재 포커스(focus)를 가진 컴포넌트가 Key 이벤트를 독점한다.

 

KeyListener

: 키 이벤트 리스너는 KeyListener를 상속받아 구현한다.

KeyListener의 3개 메소드

 

키 이벤트 리스너 달기

: addKeyListener() 메소드

component.addKeyListener(myKeyListener);

 

가상 키와 입력된 키 판별
  • char KeyEvent.getKeyChar(): 입력된 키의 유니코드 값을 리턴하며, 유니코드 키가 아닌 경우 KeyEvent.CHAR_UNDEFINED를 리턴한다.
  • int KeyEvent.getKeyCode(): 모든 키에 대해 정수형의 키 코드(key code) 값을 리턴한다.

KeyEvent 객체의 메소드로 입력된 키 판별

 

KeyEvent와 KeyListener 활용
/*
 * 예제 9-6: KeyLister 활용 - 입력된 문자 키 판별
 * <Enter> 키를 입력할 때마다 배경색을 랜덤하게 바꾸고,
 * 'q' 키를 입력하면 프로그램을 종료시켜라.
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class KeyCharEx extends JFrame {
	private JLabel la = new JLabel("<Enter> 키로 배경색이 바뀝니다.");
	public KeyCharEx() {
		super("KeyListener의 문자 키 입력 예제");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();  // 컨텐트팬 알아내기
		c.setLayout(new FlowLayout());
		c.add(la);
		c.addKeyListener(new MyKeyListener());  // 키 리스너 달기
		setSize(250, 150);
		setVisible(true);
		
		c.setFocusable(true);  // 컨텐트팬이 포커스를 받을 수 있도록 설정
		c.requestFocus();  // 컨텐트팬에 포커스 설정. 키 입력 가능해짐
	}
	class MyKeyListener extends KeyAdapter{
		public void keyPressed(KeyEvent e) {
			// 임의의 색을 만들기 위해 랜덤하게 r, g, b 성분 생성
			int r = (int)(Math.random()*256);  // 0~255 사이의 임의의 red 성분
			int g = (int)(Math.random()*256);
			int b = (int)(Math.random()*256);
			
			// 입력된 키 문자
			switch(e.getKeyChar()) {
			case '\n': // <Enter> 키 입력
				la.setText("r=" + r + ", g=" + g + ", b=" + b);
				getContentPane().setBackground(new Color(r,g,b));  // 컨텐트팬의 배경색 설정
				break;
			case 'q':
				System.exit(0);  // 프로그램 종료
				break;
			}
		}
	}
	public static void main(String[] args) {
		new KeyCharEx();
	}
}

 

/*
 * 예제 9-7: KeyListener 활용 - 상,하,좌,우 키로 문자열 움직이기
 */

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class FlyingTextEx extends JFrame {
	private JLabel la = new JLabel("HELLO");  // 키 입력에 따라 움직일 레이블 컴포넌트
	
	public FlyingTextEx() {
		super("상,하,좌,우 키를 이용하여 텍스트 움직이기");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Container c = getContentPane();
		c.setLayout(null);  // 컨텐트팬의 배치관리자 삭제
		c.addKeyListener(new MyKeyListener());
		la.setLocation(50,50);  // 레이블의 초기 위치는 (50,50)
		la.setSize(100,20);;
		c.add(la);
		setSize(200,200);
		setVisible(true);
		
		c.setFocusable(true);  // 컨텐트팬이 포커스를 받을 수 있도록 설정
		c.requestFocus();  // 컨텐트팬이 키 입력을 받을 수 있도록 포커스 강제 지정
	}
	
	// Key 리스너 구현
	class MyKeyListener extends KeyAdapter{
		public void keyPressed(KeyEvent e) {
			int keyCode = e.getKeyCode();  // 입력된 키의 키 코드를 알아낸다.
			switch(keyCode) {  // 키 코드에 따라 상,하,좌,우 키 판별, 레이블의 위치 이동
			case KeyEvent.VK_UP:  // UP 키
				la.setLocation(la.getX(), la.getY() - 10); 
				break;
			case KeyEvent.VK_DOWN:  // DOWN 키
				la.setLocation(la.getX(), la.getY() + 10);  
				break;
			case KeyEvent.VK_LEFT:  // LEFT 키
				la.setLocation(la.getX() - 10, la.getY());
				break;
			case KeyEvent.VK_RIGHT:  // RIGHT 키
				la.setLocation(la.getX() + 10, la.getY());
				break;
			}
		}
	}
	public static void main(String[] args) {
		new FlyingTextEx();
	}
}

 


9.6 Mouse 이벤트와 MouseListener, MouseMotionListener
  • Mouse 이벤트: 사용자의 마우스 조작에 따라 발생하는 이벤트

Mouse 이벤트

 

마우스 리스너 달기

마우스 리스너 달기

 

MouseEvent 객체 활용

MouseEvent 객체 활용

 

Mouse 이벤트 처리 예
/*
 * Mouse 이벤트 처리 예
 * 마우스가 컨텐트팬에 올라가면 배경색을 CYAN으로, 컨텐트팬에서 내려가면 YELLOW로 변경한다.
 */

import javax.swing.*;
import java.awt.event.*;
import java.awt.*;

public class MouseEventAllEx extends JFrame {
    private JLabel la = new JLabel("   Move Me");  // 마우스로 이동시킬 레이블 컴포넌트
    
    public MouseEventAllEx() {
        setTitle("MouseListener와 MouseMotionListener 예제");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container c = getContentPane();
        
        MyMouseListener listener = new MyMouseListener();  // 마우스/모션 리스너 객체 생성
        c.addMouseListener(listener);  // MouseListener 리스너 등록
        c.addMouseMotionListener(listener);  // MouseMotionListener 리스너 등록
        
        c.setLayout(null);  // 배치 관리자를 삭제하여 레이블을 마음대로 움직일 수 있게 함
        la.setSize(80,20);
        la.setLocation(100,80);  
        c.add(la);  // 레이블 컴포넌트 삽입
        
        setSize(320,200);
        setVisible(true);
    }
    
    // Mouse 리스너와 MouseMotion 리스너를 모두 가진 리스너
    class MyMouseListener implements MouseListener, MouseMotionListener{
        // MouseListener의 5개 메소드 구현
        public void mousePressed(MouseEvent e) {
            la.setLocation(e.getX(), e.getY());  // 마우스가 눌러진 위치로 레이블 이동
            setTitle("mousePressed(" + e.getX() + "," + e.getY() + ")");  // 눌러진 위치 출력
        }
        public void mouseReleased(MouseEvent e) {
            la.setLocation(e.getX(), e.getY());  // 마우스가 놓여진 위치에 레이블 이동
            setTitle("mouseReleased(" + e.getX() + "," + e.getY() + ")");  // 떼어진 위치 출력
        }
        public void mouseClicked(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {
            Component comp = (Component)e.getSource();
            comp.setBackground(Color.CYAN);  // 마우스가 올라간 곳 색 변경
        }
        public void mouseExited(MouseEvent e) {
            Component comp = (Component)e.getSource();
            comp.setBackground(Color.YELLOW);  // 마우스가 내려간 곳 색 변경
            setTitle("mouseExited(" + e.getX() + "," + e.getY() + ")");  // 벗어난 위치 출력
        }
        
        // MouseMotionListener의 2개 메소드 구현
        public void mouseDragged(MouseEvent e) { // 마우스가 드래깅되는 동안 계속 호출
            la.setLocation(e.getX(), e.getY());
            setTitle("mouseDragged(" + e.getX() + "," + e.getY() + ")");  // 무브 위치 출력
        }
        
        public void mouseMoved(MouseEvent e) {
            // 마우스가 이동할 때 호출
        }
    }
    
    public static void main(String[] args) {
        new MouseEventAllEx();
    }
}