▶ 이벤트 처리
- 키보드나 마우스를 클릭하거나 마우스를 움직이는 등의 컴퓨터 내의 동작들을 이벤트(Event)가 발생했다고 하며, 해당 동작들을 어떻게 처리할지 결정하는 것을 이벤트 처리라고 한다. 해당 이벤트는 이벤트 리스너(Event Listener) 객체를 생성하여 처리한다.
- 이벤트-구동 프로그래밍(Event-Driven Programming) : 대부분의 프로그램은 알고리즘에 의해 문장들이 차례대로 실행된다. 그러나 이벤트-구동 프로그래밍의 경우 순서에 상관없이 이벤트가 발생함에 따라 프로그램을 실행한다.
▶ 이벤트 객체
- 이벤트가 발생했을 때, 해당 이벤트를 처리하기 위해 이벤트를 보관 또는 저장하는 객체라고 생각하면 될 것이다.
- 모든 이벤트 객체는 EventObject 클래스를 상속받는다.
- EventObject 클래스는 getSource() 메소드를 가지고 있으며, 이 메소드는 해당 이벤트를 일어나게 만든 이벤트 소스를 반환한다. 이벤트 소스란 어떤 원인(버튼 클릭, 키보드 입력 등)에 의해 이벤트가 발생했는지를 알려준다. 단, 리턴 타입이 Object 이므로 필요한 타입으로 타입 변환하여 사용해야 한다.
▶ 이벤트 리스너(Event Listener)
- 이벤트가 발생하면 이벤트에 대한 다양한 정보를 가진 이벤트 객체가 생성된다. 이 때, 발생된 이벤트 객체에 반응하여 이벤트를 처리하는 객체를 의미한다. 리스너는 인터페이스이므로 리스너 인터페이스를 구현하는 클래스와 이벤트 객체를 연결하면 된다.
- 이벤트 리스너 등록하기
public class Test extends JFrame {
//FIELDS
JButton button = new JButton("버튼“);
//CONSTRUCTOR
public Test() {
// 리스너를 등록할 때 매개변수로 이벤트 리스너 인스턴스(클래스)를 넘긴다.
button.addActionListener(new EventListenerA());
...
}
}
- 이벤트 소스에 이벤트 리스너가 등록되어 있다면, 이벤트 발생 시 이벤트 리스너 내부의 이벤트 처리 메소드가 자동 호출된다. 등록된 리스너가 없으면 아무 일도 발생하지 않는다. (컴포넌트의 addXXXXListener() 메소드 호출)
- 이벤트 리스너를 생성하는 방법은 다양하다.
1. 리스너를 독립적인 클래스로 생성
=> 리스너 클래스가 이벤트가 발생한 클래스 내부의 멤버로 접근하는 것이 어렵다.
//이벤트 리스너를 구현하는 독립적인 클래스
class ListenerExample implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
...//이벤트 처리 코드 작성
}
}
class FrameExample extends JFrame {
//FIELDS
private JButton button = new JButton("button");
//CONSTRUCTOR
public FrameExample() {
...
button.addActionListener(new ListenerExample()); //리스너는 필드에 선언해도 상관없다.
...
}
}
public class Main() {
public static void main(String[] args) {
FrameExample fe = new FrameExample();
}
}
2. 내부 클래스로서 리스너 클래스를 생성
=> 내부 클래스는 외부 클래스의 멤버 변수들을 자유롭게 사용할 수 있다.
//이벤트 리스너를 구현하는 중첩 클래스 - 인스턴스 멤버 클래스
class FrameExample extends JFrame {
//FIELDS
private JButton button = new JButton("button");
//CONSTRUCTOR
public FrameExample() {
...
button.addActionListener(new ListenerExample()); //리스너는 필드에 선언해도 상관없다.
...
}
private class ListenerExample implements ActionListener { //중첩 클래스
@Override
public void actionPerfomed(ActionListener e) {
...//이벤트 처리 코드 작성
}
}
}
public class Main() {
public static void main(String[] args) {
FrameExample fe = new FrameExample();
}
}
3. 해당 클래스가 이벤트를 바로 처리
=> actionPerformed(ActionEvent e) 메소드를 클래스 내부에 생성한다.
//해당 클래스가 이벤트 리스너를 구현한다.
class FrameExample extends JFrame implements ActionListener {
//FIELDS
JButton button = new JButton("button");
//CONSTRUCTOR
public FrameExample() {
...
button.addActionListener(this); //자기 자신이 리스너의 구현 클래스이므로 this를 매개변수로 준다.
...
}
//METHODS
@Override
public void actionPerformed(ActionListener) {
...//이벤트 처리 코드 작성
}
}
public class Main() {
public static void main(String[] args) {
FrameExample fe = new FrameExample();
}
}
4. 이벤트를 한번만 사용할 경우 무명 클래스 사용 (익명 객체)
=> 코드가 정의되자마자 바로 사용됨.
//처리하는 이벤트가 적은 경우에 주로 사용되며, 이벤트를 일으키는 컴포넌트가 많은 경우에는 추천하지 않는다.
class FrameExample extends JFrame implements ActionListener {
//FIELDS
JButton button = new JButton("button");
//CONSTRUCTOR
public FrameExample() {
...
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == button)) { ... }
}
});
...
}
}
public class Main() {
public static void main(String[] args) {
FrameExample fe = new FrameExample();
}
}
5. 이벤트 핸들러 클래스 사용
=> 하나의 문장으로 간단하게 이벤트 리스너를 생성하므로 코드의 간결화를 유도한다.
//아주 간단한 타입의 이벤트 리스너에 대해서만 유용하다.
class FrameExample extends JFrame implements ActionListener {
//FIELDS
JButton button = new JButton("button");
//CONSTRUCTOR
public FrameExample() {
...
button.addActionListener((ActionListener) EventHandler.create(ActionListener.class, JFrame명, 메소드명));
...
}
}
public class Main() {
public static void main(String[] args) {
FrameExample fe = new FrameExample();
}
}
▶ 이벤트 종류
모든 컴포넌트가 제공하는 이벤트 | |
ComponentEvent | 컴포넌트 위치 및 크기가 변경되면 발생 |
FocusEvent | 키보드 입력을 받거나 입력을 받지 않는 경우에 발생 |
ContainerEvent | 컨테이너에 컴포넌트가 추가 혹은 삭제될 경우 발생 |
KeyEvent | 키를 누르면, 키보드 포커스를 가지고 있는 객체에서 발생 |
MouseEvent | 마우스가 Clicked, Pressed, Released, Entered, Exited의 상황에서 발생 |
MouseMotionEvent | 마우스가 움직였을 때 발생 |
MouseWheelEvent | 컴포넌트 위에서 마우스 휠을 움직이면 발생 |
WindowEvent | 윈도우가 열리거나 닫히거나 아이콘화 되는 등과 같이 어떤 변화가 있을 때 발생 |
일부 컴포넌트만 제공하는 이벤트 | |
ActionEvent | 사용자가 어떤 동작을 할 경우 발생 해당 컴포넌트 : JButton, JCheckBox, JComboBox, JFileChooser, JMenuItem, JRadioButton, JTextField |
CaretEvent | 텍스트 삽입점이 이동하거나 텍스트 선택이 변경될 경우 발생 해당 컴포넌트 : JTextArea, JTextField |
ChangeEvent | 객체의 상태가 변경되었을 경우 발생 해당 컴포넌트 : JButton, JCheckBox, JColorChooser, JMenuItem, JProgressBar, JRadioButton, JSlider, JSpinner |
DocumentEvent | 문서의 상태가 변경되는 경우 발생 해당 컴포넌트 : JTextArea, JTextField |
ItemEvent | 선택 가능한 컴포넌트에서 사용자가 선택하는 경우 발생 해당 컴포넌트 : JButton, JCheckBox, JComboBox, JMenuItem, JRadioButton |
ListSelectionEvent | 테이블이나 리스트에서 선택이 변경되면 발생 해당 컴포넌트 : JList, JTable |
TreeSelectionEvent | 트리 구조의 컴포넌트에서 선택이 변경되면 발생 |
▶ 리스너 인터페이스 요약
리스너 인터페이스 | 어댑터 클래스 | 메소드 |
ActionListener | X | actionPerformed() |
AdjustmentListener | X | adjustmentValueChanged() |
ComponentListener | ComponentAdapter | componentHidden(), componentMoved(), componentResized(), componentShown() |
ContainerListener | ContainerAdapter | componentAdded(), componentRemoved() |
FocusListener | FocusAdapter | focusGained(), focusLost() |
ItemListener | X | itemStateChanged() |
KeyListener | KeyAdapter | KeyPressed(), KeyTyped(), KeyReleased() |
MouseListener | MouseAdapter | mouseClicked(), mouseEntered(), mouseExited(), mousePressed(), mouseReleased() |
MouseMotionListener | MouseMotionAdapter | mouseDragged(), mouseMoved() |
TextListener | X | textValueChanged() |
WindowListener | WindowAdapter | windowActivated(), windowClosed(), windowClosing(), windowDeactivated(), windowDeiconified(), windowIconified() windowOpened() |
▶ 어댑터 클래스
- 이벤트를 처리하기 위해서는 리스너 인터페이스에서 정의되어 있는 모든 메소드를 구현해야 한다. 따라서 원하는 메소드가 하나뿐인 경우에도 인터페이스의 모든 메소드를 구현해야 하는 불편함이 있다.
- 어댑터 클래스(Adapter Class)는 각 리스너(Listener)에 대응되는 클래스로, 원하는 메소드만을 구현하는 것이 가능하다.
- 리스너는 인터페이스고 어댑터는 클래스의 형태로 제공되기 때문에 리스너를 사용할 때는 implements 키워드를, 어댑터를 사용할 때는 extends 키워드를 사용해야 한다.
- 자바에서는 다중 상속을 허용하지 않기 때문에 두 개의 클래스를 동시에 상속받을 수 없다. 따라서 어댑터 클래스를 내부 클래스(중첩 클래스)로 정의하여 사용한다.
- 리스너의 메소드가 하나인 의미적 메소드의 경우 대응하는 어댑터 클래스가 없다.
public class MyFrame extends JFrame {
MyFrame() {
...
addKeyListener(new MyKeyAdapter());
...
}
class MyKeyAdapter extends KeyAdapter {
@Override
public void keyTyped(KeyEvent e) { //하나의 메소드만 처리 가능
...//이벤트 처리 코드 작성
}
}
}
'Programming Language > JAVA' 카테고리의 다른 글
20. ComponentEvent, ContainerEvent, FocusEvent, WindowEvent - 컴포넌트 이벤트, 컨테이너 이벤트, 포커스 이벤트, 윈도우 이벤트 (0) | 2017.05.26 |
---|---|
19. ActionEvent, KeyEvent, MouseEvent - GUI에서 잘 쓰이는 이벤트 (0) | 2017.05.26 |
17. Graphics Programming - 그래픽 프로그래밍 (0) | 2017.05.24 |
16. LayoutManager - 배치관리자 (0) | 2017.05.24 |
15. Graphical User Interface (GUI) - 그래픽 사용자 인터페이스 개요 (0) | 2017.05.24 |