국비교육(22-23)

20일차(1)/java(26) : Frame(2)

서리/Seori 2022. 11. 2. 14:31

 

패키지02 MyFrame

package frame02;

import java.awt.FlowLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyFrame extends JFrame{
	//생성자
	public MyFrame(String title) {
		super(title);
		setBounds(100,100,500,500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//흐르듯이 배치하는 레이아웃
		setLayout(new FlowLayout(FlowLayout.LEFT));
		
		JButton btn1=new JButton("버튼1");
		add(btn1); //프레임에 btn1 추가하기
		
		JButton btn2=new JButton("버튼2");
		add(btn2);
		
		JButton btn3=new JButton("버튼3");
		add(btn3);
		
		setVisible(true);	
	}
	
	public static void main(String[] args) {
		new MyFrame("나의 프레임2");
	}
}

 

.setBounds(x,y,w,h) : x,y축 위치와 너비,높이 값을 받아 그 크기의 창을 생성

 

.setLayout(); : 레이아웃매니저 타입을 받아 해당 레이아웃으로 객체를 생성

 

- 메인메소드에서 new MyFrame("나의 프레임2") 에 이름넣으면 상단의 title로 전달된다.

 

- run해보면 버튼 3개가 생성되었다.

 

 

- 위에서부터 물 흐르듯이 배치되는 것을 flowLayout이라 한다.

- 창 크기를줄이면 알아서 좁게 배치되고, 기본은 가운데정렬이다.

- new FlowLayout(FlowLayout.LEFT); 하면 좌측정렬시킬 수도 있다.

 

- 들어갈 수 있는 타입이 LayoutManager 타입인데, new FlowLayout이 들어가진다는 것은,

  FlowLayout은 상속받는 부모타입중에 LayoutManager가 있다는 뜻!

 

* FlowLayout 설명 : 링크

 


 

패키지03 MyFrame

package frame03;

import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyFrame extends JFrame{
	//생성자
	public MyFrame(String title) {
		super(title);
		setBounds(100,100,500,500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//격자모양으로 배치하는 레이아웃
		setLayout(new GridLayout(2,2));
		
		JButton btn1=new JButton("버튼1");
		add(btn1); //프레임에 btn1 추가하기
		
		JButton btn2=new JButton("버튼2");
		add(btn2);
		
		JButton btn3=new JButton("버튼3");
		add(btn3);
		
		JButton btn4=new JButton("버튼4");
		add(btn4);
		
		setVisible(true);	
	}
	
	public static void main(String[] args) {
		new MyFrame("나의 프레임3");
	}
}

- GridLayout

 

 

GridLayout(); : 격자형 레이아웃 (기본형태)

 

setLayout(new GridLayout(2,2));

- 위와 같은 형태로 입력하면 2*2 의 격자 모양으로 배치된다.

 


 

패키지04 MyFrame

package frame04;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MyFrame extends JFrame{
	//생성자
	public MyFrame(String title) {
		super(title);
		setBounds(100,100,500,500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//경계선을 따라 배치하는 레이아웃
		setLayout(new BorderLayout());
		
		JButton btn1=new JButton("버튼1");
		add(btn1, BorderLayout.NORTH);		
		
		JButton btn2=new JButton("버튼2");
		add(btn2, BorderLayout.EAST);
		
		JButton btn3=new JButton("버튼3");
		add(btn3, BorderLayout.SOUTH);
		
		JButton btn4=new JButton("버튼4");
		add(btn4, BorderLayout.WEST);
		
		setVisible(true);	
	}
	
	public static void main(String[] args) {
		new MyFrame("나의 프레임4");
	}
}

- Border Layout

 

- 상하좌우의 경계선(border)을 따라 배치한다!

 

- 다중정의된 add 중에서 Component, Object 인자를 받는 메소드로 사용

 

add(btn1, "North");

- 어느 쪽 border를 기준으로 할 것인지 옵션값을 따로 지정할 수도 있다.

 

 

- 이런 값은 미리 상수로도 만들어져 있다.

BorderLayout.NORTH(EAST/SOUTH/WEST) 로 입력해도 결과는 같다.

→ (상수화하는 이유) 잘 기억하고 쉽게 사용할 수 있도록 복잡한 문자열에 이름을 부여해주는 것!

 


 

패키지05 MyFrame

package frame05;


import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MyFrame extends JFrame{
	//생성자
	public MyFrame(String title) {
		super(title);
		
		//this 예약어를 이용해서 MyFrame 객체의 다형성 확인!
		MyFrame a=this;
		JFrame b=this;
		Component c=this;
		Object d=this;
		
		setBounds(100,100,500,500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		JButton sendBtn=new JButton("전송");
		add(sendBtn);
		//ActionListener 인터페이스 type의 참조값 얻어내서
		ActionListener listener=new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.out.println("전송 버튼을 눌렀네?");
				
				JOptionPane.showMessageDialog(MyFrame.this, "전송합니다");
				
				ActionListener f=this;
				//Component f=this; (X) 
				Component g=MyFrame.this; 
			}			
		};
		//전송버튼에 등록하기
		sendBtn.addActionListener(listener);
		
		/*
		 * 삭제 버튼도 프레임에 배치하고, 해당 버튼을 눌렀을 때 "삭제 버튼을 눌렀네?"라는
		 * 메세지를 콘솔창에 출력되도록 프로그래밍 해보세요.
		 */
		JButton deleteBtn=new JButton("삭제");
		add(deleteBtn);		
		ActionListener listener2=new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				System.out.println("삭제 버튼을 눌렀네?");
				JOptionPane.showMessageDialog(MyFrame.this, "삭제합니다");
			}						
			
		};
		/* deleteBtn.addActionListener((msg)->
		*	System.out.println("삭제 버튼을 눌렀네?"));
		*/
		deleteBtn.addActionListener(listener2);	

	}
	
	public static void main(String[] args) {
		MyFrame f=new MyFrame("나의 프레임5");
		f.setVisible(true);
	}
}

 

- 메인 메소드 안에서 setVisible 을 실행하고 싶다면?

 

- 메인메소드 안에서 선언한 f 라는 변수 안에 참조값을 넣어주면

  f는 myFrame 메소드 안의 this와 같은 기능을 가질 수 있다.

 

- static 영역에 클래스가 올라가고(메인메소드에서 생성), heap영역에 객체가 생기는데(new로 생성)

 f 에 참조값(24)이 들어가므로 f.  과 this. 는 같은 역할로 사용될 수 있다!

 


 

- 버튼을 클릭할 때마다 어떤 메소드가 실행되도록 하고 싶다면?

 

 

* javascript

<button id="one">
<script>
	document.querySelector("#one").addEventListner("click", Function(){});
</script>

→ document.querySelector 으로 참조값을 얻어내고, 버튼을 클릭할 때마다 함수가 호출된다.
- 함수를 등록해뒀다가 call 되도록 하는데, 함수가 단독으로 존재할 수 있기 때문에 이게 가능한 것이다.

* java

- java에서는 특정 객체에 있는 특정 메소드가 호출되도록 해야 한다.
- JButton을 눌렀을 때 단순히 메소드가 호출되는 게 아니라 특정 객체에있는 메소드가 필요함!
→ JButton에 어떤일이 일어났을 때 호출될 메소드를 갖고있는 객체를 등록해야 한다.
   약속된 메소드가 호출될 수 있도록!

- 이때 객체의 타입은 이미 설계되어 있음

.addActionListener( ); : 호출될 객체를 등록하는 메소드!
- () 안에는 반드시 호출될 메소드를 갖고 있는 객체 타입이 들어가야 한다.

 

- addActionListener 안에 들어갈 인자인 ActionListener의 타입을 확인해보니 인터페이스 타입이다.

 

- 참조값을 얻어내서 전송버튼의 인자로 전달할 수 있도록 하는 것.

 

- new ActionListener이라고 쓰면 오류가 발생한다.

 인터페이스 타입은 단독 객체를 생성하지 못하기 때문에!

→ 이름 없는 익명클래스로 만들어주고 override하면 된다.

 

- 추상메소드 한개이므로 람다식으로도 작성할 수 있다.

 

- 이제 버튼을 클릭할 때마다 actionPerformed 메소드가 실행된다.

- 클릭시 실행시키고 싶은 기능이 있다면 저 메소드 안에 넣으면 된다!

 


[ MyFrame의 다형성 ]

MyFrame a=this;
JFrame b=this;
Component c=this;
Object d=this;

 


- 위 this는 MyFrame의 참조값을 가리키는 것이고
  아래 this는 익명클래스안에서 생성한 객체의 참조값을 가리키는 것!

 

- innerclass 안에서 this 사용하기

ActionListener f=this; (O)  → ActionListener 타입을 가리킨다.
Component f=this; (X)  → ActionListener 타입, 외부클래스 MyFrame을 의미하지 않는다.
Component g=MyFrame.this; (O)  → MyFrame을 가리킨다.

 

 

- inner class 안에서 밖에 있는 outer class의 객체의 참조값을 가리키고 싶다면 outerclass.this 형태로 쓰면 된다.

 → 바깥클래스명.this  ex) Myframe.this

 

 

.showMessageDialog( , ) : Frame 위에 메시지 창를 띄우는 메소드이고, 2개의 인자를 받는다.

- Component 타입 : 어느 Component에 띄울 것인지(MyFrame의 참조값)

- String 타입: 어떤 내용을 띄울 것인지

 

JOptionPane.showMessageDialog(MyFrame.this, "전송합니다");

- 그냥 this라고 쓰면 받아지지 않는다. Component 타입을 넣어야 하기 때문에!

- 그래서 Myframe.this 라고 써준다.

 

분홍: 어떤 작업을 할 것인지(알림창 띄우기)

초록: 알림 메세지를 어느 프레임에다가 띄울 것인지

빨강: 알림창에 어떤 내용을 띄울 것인지

 

- 각각의 코드가 의미하는 바를 제대로 이해하기!

 

- 버튼의 동작을 구현하는 데 익명클래스를 사용한 예제

 


 

패키지06 MyFrame

- 똑같이 버튼의 동작을 구현하는데, 05와 다른 방법 사용하기!

package frame06;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class MyFrame extends JFrame implements ActionListener{
	//필드
	JButton sendBtn;
	JButton deleteBtn;
	//생성자
	public MyFrame(String title) {
		super(title);
				
		setBounds(100,100,500,500);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(new FlowLayout());
		
		//객체 생성해서 참조값을 필드에 저장
		sendBtn=new JButton("전송");
		add(sendBtn);
		
		deleteBtn=new JButton("삭제");
		add(deleteBtn);		
		
		sendBtn.addActionListener(this);
		deleteBtn.addActionListener(this);
	}
	
	public static void main(String[] args) {
		MyFrame f=new MyFrame("나의 프레임6");
		f.setVisible(true);
	}
	/*
	 * 전송버튼, 삭제버튼을 누르면 호출되는 메소드
	 * 메소드 안에서 어떤 버튼을 눌렀는지 확인해서 분기해야한다.
	 * 메소드에 선언된 매개변수 ActionEvent e에 눌러진 버튼에 대한 정보갸 담겨 있다.
	 * 해당 객체를 활용해서 분기를 하면 된다.
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		//눌러진 버튼의 참조값 얻어내기
		Object which=e.getSource();
		
		if (which == sendBtn) {
			JOptionPane.showMessageDialog(this, "전송합니다");
		}else if(which == deleteBtn) {
			JOptionPane.showMessageDialog(this, "삭제합니다");
		}		
	}
}

 

먼저 sendBtn 을 구현하는데,

 

sendBtn.addActionListener(this);

- () 에 ActionListener 타입을 넣어야하는데, this가 Frame타입이라서 안 받아준다.

→ 그렇다면 Frame에 ActionListener(인터페이스)를 구현하면 된다.

   구현한 후에 미완성 메소드를 @override 해주면 ActionListener 타입으로 받아들여준다.

 

- 인터페이스를 구현해서 사용하니 익명클래스를 사용하는것보다 좀더 간단하고 단순하다.

 

 

- 하지만 delete 버튼까지 같이 구현하려면? 아래와 같이 버튼 이름만 바꾼 같은 코드로는 사용할 수 없다.

deleteBtn.addActionListener(this);

JOptionPane.showMessageDialog(this, "삭제합니다");

 

- 분기를 나누어야 한다. 특정 버튼이 눌러졌을 때 각각 다른 분기로 실행되도록!

- 어떤 버튼이 눌러졌는지 확인할 수 있는 수단이 필요.

.getSource() : 어떤 액션이 일어난 ui(눌러진 버튼)의 참조값이 object타입으로 반환된다.

 

- 이렇게 분기를 나눠서 작동할 수 있도록 버튼값을 참조해야 하는데,

  sendBtn, deleteBtn은 local변수라서 오류가 발생한다. 포함된 메소드 밖에서는 참조할 수 없다.

- MyFrame 안에 있는 변수인 sendBtn을 참조하려면 어떻게 해야 하는가?

 

→ 이렇게 객체 안의 다른 메소드에서 필요한 값은 지역변수가 아닌 필드에 담는 것이 좋다.

 

JButton sendBtn=new JButton("전송");  → sendBtn 지역변수를 선언하고 안에 참조값을 넣는 것

this.sendBtn=new JButton("전송");  → sendBtn 필드에 참조값을 넣는 것(this. 은 생략가능)

- 이와 같이 필드에 값을 넣어놓으면 객체 안에서 어디서든 참조해서 쓸 수 있다.

 

- 이렇게 하면 어떤버튼을 눌렀는지 알아내고 분기시켜서 사용할 수 있다!

 

 

- ActionEvent e 액션이벤트 객체는 우리가 생성하는 것이 아니다.

 알아서 생성되어서 전달될 것이라는 걸 기대하고 작성하면 된다.