interface가 하나 이상의 추상 method를 가진다면 사용의 편의성을 위해 ~Adapter Class를 제공
이벤트 처리를 Is-A 관계로 처리하는 방법
디자인과 이벤트 처리를 하나의 클래스안에서 처리한다.
값에 대한 사용이 편하다.
한 클래스에서 상속으로 Frame을 받고 구현으로 OOOListener를 처리
이벤트처리와 관련있는 Component를 선언
Component를 생성
컴포넌트가 이벤트를 발생할 수 있도록 등록
// 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@Overridepublic void actionPerformed(ActionEvent ae) { // 이벤트가 발생했을 때 처리}
/*** 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(); }}
이벤트처리를 Has-A 관계로 처리하는 방법
디자인과 이벤트처리 코드를 분리할 수 있다.
클래스가 늘어난다.
값 넘기기 어렵다.
에러처리가 복잡해진다.
Design 클래스
Frame 상속받는 클래스 생성
이벤트 관련 Component를 선언
컴포넌트 생성
이벤트 처리객체 생성하고 Has-A관계 설정
이벤트 등록
// 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 클래스
OOOListener를 구현하는 클래스 생성
디자인 클래스를 Has-A 관계로 가지고 사용할 수 있도록 선언
생성자에서 디자인 클래스를 받는다.
추상 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 Overridepublic void actionPerformed(ActionEvent e) { // 이벤트가 발생했을 때 처리}
/*** 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(); }}
이벤트처리를 inner class로 처리하는 방법
디자인에 해당하는 이벤트처리 코드가 매우 적거나 특정디자인에 해당하는 이벤트만 처리할 때
디자인 클래스안에서 여러 이너 클래스로 이벤트를 구분하여 처리가능
윈도우 컴포넌트를 상속
이벤트 처리와 관계된 컴포넌트 선언
생성
이벤트를 처리하기 위한 inner class를 작성
추상 메소드 Override
이벤트 등록
// 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(); }}
Anonymous inner class
이벤트 처리 코드의 재사용성이 낮은 방법
Window Component를 상속
Component를 선언
생성
이벤트 등록
// 1. Window Component를 상속public class Test extends Frame { ... }// 2. Component를 선언Button btn;// 3. 생성public Test() { btn = new Button();}// 4. 이벤트 등록// anonymous inner classbtn.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(); }}
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(); } }}
이벤트처리 구현 예시(01)
입력버튼이 클릭되면 TextField의 입력값을 가져와서 TextArea에 추가할 것
"입력" 버튼클릭 -> ActionEvent
ActionListener, 등록은 addActionListener(처리될 곳)
TF에서 값 가져오는건 TextComponent 클래스의 getText 사용
TA에 TextArea의 append를 사용해서 가져온 text를 추가
Is-A 구현시
// 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(); }}
이벤트처리 구현 예시(02)
List 아이템을 클릭하면 라벨에 해당 아이템의 정보를 표시할 것
ItemEvent 처리
ItemListener 인터페이스 사용
리스트컴포넌트.addItemListener 사용
리스트 클릭 했을 때 **getSelectedItem()**로 선택한 item 받기
리스트를 선택했을 때 선택한 리스트의 인덱스를 얻는 **getSelectedIndex()**도 존재
**getItem(int index)**랑 같이 사용가능
Is-A 구현시
/*** 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()); }}