이벤트가 발생했을 때 어떤 동작을 수행하기 위해서는 컴포넌트와 이벤트 리스너를 서로 연결해야함
⇒ 컴포넌트 객체의 addXXXListener() 메서드를 호출하여 리스너 객체 전달
ex) btn.addActionListener(리스너 객체);
< 이벤트 처리(Event Handling) >
컴포넌트에 특정 이벤트가 발생했을 때 수행할 동작을 지정하여 처리하는 것
리스너(Listener) 내에 수행할 동작을 명시
⇒ 주로 XXXListener 인터페이스 또는 XXXAdapter 클래스가 제공됨
리스너 객체를 직접 구현하거나 별도의 핸들러 클래스를 사용하여 상속받아 구현
리스너 인터페이스는 주로 java.awt.event 패키지 내에 위치함
======== JAVA0420
지난 시간에 했던 event 그대로 src로 이동시키기(드래그)
======== Test_Stage_1.java 만들기
package event_handling; import javax.swing.JButton; import javax.swing.JFrame; public class Test_Stage_1 extends JFrame { public Test_Stage_1() { showFrame(); } public void showFrame() { setTitle("1단계 이벤트 처리"); setBounds(600, 400, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // JButton 컴포넌트 생성 및 부착 JButton btn = new JButton("버튼"); add(btn); setVisible(true); } public staticvoid main(String[] args) { new Test_Stage_1(); } }
실행창
클래스 밖에 만들기 & 빨간 밑줄 눌러서 Add~ 로 자동 추가해주기
@Override public void actionPerformed(ActionEvent e) { // 버튼 클릭 시 자동으로 호출되는 메서드 System.out.println("버튼 클릭!"); }
Add~ 로 추가 시 이렇게 자동으로 생성됨
// JButton 컴포넌트에 ActionListener 를 연결하여 이벤트 처리 // ⇒ addXXXListener() 메서드 호출 // 1단계. 리스너를 구현하는 서브클래스 사용 MyActionListener listener = new MyActionListener(); btn.addActionListener(listener);
showFrame(); 안에 추가해주기
누를 때 마다 동작함! ⇒ ActionListener 인터페이스는 추상메서드가 1개이므로 ActionAdapter 가 없음
class MyInnerWindowAdapter extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { // 창 닫기 버튼 클릭 시 호출되는 메서드 System.out.println("windowClosing"); System.exit(0); // 프로그램 종료 } }
추가
내부클래스에서는 외부클래스(Ex_Stage_3)의 멤버에 자유롭게 접근 가능
public void showFrame() { setTitle("이벤트 처리 - 3단계"); setBounds(600, 400, 300, 200); // 이벤트 처리 3단계. 내부 클래스 사용 MyInnerWindowAdapter listener = newMyInnerWindowAdapter(); addWindowListener(listener); setVisible(true); }
오류 안남! ⇒ 익명 인스턴스 내부 클래스 형태로 정의되었으므로 다른 메서드에서도 접근 가능한 객체
이벤트 처리 4단계. 익명 내부 클래스 사용
⇒ 별도의 인스턴스 생성 없이 바로 익명클래스 타입 변수 사용
⇒ 메서드 내에서 정의한 익명 로컬 내부 클래스이므로 다른 메서드에서는 접근이 불가능하고, 현재 메서드에서만 접근 가능한 객체
이런식으로 접근할때는 자동완성으로 하기! {}; 가 익숙하지 않기 때문
추상메서드를 자동으로 만들어준다!
WindowListener 인터페이스를 사용한 익명 내부 클래스
변수 선언, 클래스 정의, 생성까지 한번에 가능!
======== Test_Stage_4.java (Test_Stage_3.java 복사)
> 4단계로 바꿔보기!
4단계. 익명 인스턴스 내부 클래스 형태로 정의
4단계. 익명의 로컬 내부클래스 사용
왜 listener 라고 변수에 저장해서 사용할까? - 매번 접근할 수 있기 때문에(재사용)
근데 여기선 listener를 한 번만 사용함! 그럼 굳이 변수가 필요할까
⇒ 5단계로 넘어가보자!
임시객체 : 재사용 불가
======== Ex_Stage_5.java (Ex_Stage_4.java 복사)
< 이벤트 처리 5단계 >
익명 내부 클래스의 임시 객체 형태로 정의하여 사용
⇒ 익명 내부 클래스 형태는 동일하나 객체를 한 번 사용하고 끝낼 경우 객체의 주소를 저장하는 참조변수도 필요없으므로 객체가 필요한 파라미터에 객체 생성 코드를 바로 명시하는 것 ( 임시객체 : 재사용 불가 )
⇒ 동일한 객체를 사용해야할 경우 객체 생성 코드를 중복으로 작성해야함
package event_handling; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; import javax.swing.JFrame; public class Ex_Stage_5 extends JFrame { public Ex_Stage_5() { showFrame(); } public void showFrame() { setTitle("이벤트 처리 - 5단계"); setBounds(600, 400, 300, 200); // 이벤트 처리 5단계. // 익명 내부 클래스의 임시 객체 형태로 정의하여 사용 // ⇒ 익명 내부클래스 형태는 동일하나 // 객체를 한 번 사용하고 끝낼 경우 // 객체의 주소를 저장하는 참조변수도 필요없으므로 // 객체가 필요한 파라미터에 객체 생성 코드를 바로 명시하는 것 addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.out.println("windowClosing"); System.exit(0); } }); setVisible(true); } public staticvoid main(String[] args) { new Ex_Stage_5(); } }
new 해서 자동완성 하기! (익명이라 Anonymous~)
오버라이딩 추가
완성!
→ 안드로이드 쓸 때는 이게 초반에 나옴….ㅎ
======== Test_Stage_5.java (Test_Stage_4.java 복사)
> 똑같이 만들어보기
package event_handling; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; public class Test_Stage_5 extends JFrame { public Test_Stage_5() { showFrame(); } public void showFrame() { setTitle("5단계 이벤트 처리"); setBounds(600, 400, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // JButton 컴포넌트 생성 및 부착 JButton btn = new JButton("버튼"); add(btn); // JButton 컴포넌트에 ActionListener 를 연결하여 이벤트 처리 btn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("버튼 클릭!"); } }); setVisible(true); } public staticvoid main(String[] args) { new Test_Stage_5(); } }
객체를 재사용할 때는 4단계 사용, 재사용하지 않을 때는 임시객체(1회용)를 사용하는 5단계 사용! (4,5단계, 그 중에서도 5단계를 가장 많이 사용! 특히 안드로이드에서!)
import javax.swing.JFrame; public class Ex extends JFrame { public Ex() { showFrame(); } public void showFrame() { setBounds(600, 400, 300, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } public staticvoid main(String[] args) { new Ex(); } }
Build 열기 (오른쪽 창 보임)
import javax.swing.JFrame; public class Ex { public Ex() { showFrame(); } public void showFrame() { //JFrame f = new JFrame(); //f.setBounds(600, 400, 300, 200); //f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //f.setVisible(true); //setBounds(600, 400, 300, 200); //setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //setVisible(true); } public staticvoid main(String[] args) { new Ex(); } }
바깥 선택됨
false 로 바꾸면 실행했을 때 사이즈 조절 안됨
코드로 돌아가면 자동으로 붙어있다 (둘은 연동되어 있음)
안쪽 선택됨
JButton 눌러보기
여기에 마우스 갖다대면 바뀜! (클릭하면 그 위치에 붙는다!)
누르면 버튼 생김
다시 버튼 만들어보기
또 생성됨
코드로 돌아가보면 이렇게 자동으로 생성되어있다!
getContentPane() 눌러보기 → Layout 보기!
우리가 상속받은 건 JFrame
⇒ JFrame 객체(프레임)의 기본 레이아웃(별도 설정 없으면 BorderLayout 적용됨)
// 텍스트 1줄 입력이 가능한 컴포넌트 : JTextField JTextField tf = new JTextField(); // JTextField 컴포넌트 CENTER 영역에 부착 add(tf, BorderLayout.CENTER); // OK 버튼 SOUTH 영역에 부착 JButton btnOk = new JButton("OK"); add(btnOk, BorderLayout.SOUTH); // OK 버튼 리스너 연결 - 5단계 btnOk.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { } });
btnOk.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // JTextField 컴포넌트에 입력된 텍스트 가져와서 출력 String str = tf.getText(); System.out.println("입력 데이터 : " + str); } });