9장_자바의 GUI, AWT와 Swing

IkSun·2023년 5월 30일

CHAPTER 09 자바 GUI 기초, AWT와 스윙(Swing)

9.1 자바의 GUI
9.2 자바 GUI 패키지
9.3 스윙 GUI 프로그램 만들기
9.4 컨테이너(Container)와 배치(Layout)
9.5 FlowLayout 배치관리자
9.6 BorderLayout 배치관리자
9.7 GridLayout 배치관리자
9.8 배치관리자 없는 컨테이너


자바의 GUI

  • GUI 목적
    • 그래픽 이용, 사용자에게 이해하기 쉬운 모양으로 정보 제공
    • 사용자는 마우스나 키보드를 이용하여 쉽게 입력
  • 자바 GUI 특징
    • 강력한 GUI 컴포넌트 제공
    • 쉬운 GUI 프로그래밍
  • 자바의 GUI 프로그래밍 방법
    • GUI 컴포넌트 이용
      • AWT 패키지와 Swing 패키지

AWT와 Swing 패키지

  • AWT(Abstract Windowing Toolkit)
    • 자바가 처음 나왔을 때 함계 배포된 GUI 라이브러리
    • java.awt 패키지
    • native(운영체제) 와 응용프로그램 사이의 연결 라이브러리
      • 중량 컴포넌트(Heavy weight components)
        • AWT 컴포넌트는 native(peer)에 의존적임
        • OS 의 도움을 받아야 화면에 출력되며 동작하는 컴포넌트, 운영체제에 많은 부담, 오히려 처리 속도는 빠름
  • Swing(스윙)
    • AWT 기술을 기반으로 순수 자바 언어로 작성된 라이브러리
      • 모든 AWT 기능 + 추가된 풍푸하고 화려한 고급 컴포넌트
      • AWT 컴포넌트에 J자가 덧붙여진 이름의 클래스
      • 그 외 J 자로 시작하는 클래스
    • javax.swing 패키지
    • Swing 컴포넌트는 native(peer 혹은 운영체제)에 의존하지 않음
      • 경량 컴포넌트(Light weight components)

스윙 컴포넌트 예시

  • JButton, JList, ...

GUI 라이브러리 계층 구조

  • AWT 클래스 : 그래픽 처리
  • Swing 클래스 : 자바에서 부가적으로 추가된 기능을 수행하는 역할, AWT 를 좀더 예쁘게 만드는 역할

Swing 클래스의 특징

  • 클래스 이름이 J 자로 시작
  • 화려하고 다양한 컴포넌트로 쉽게 GUI 프로그래밍
  • 스윙 컴포넌트는 2가지 유형
    • JComponent는 상속받는 클래스 (대부분의 스윙 컴포넌트)
    • AWT 의 Container 를 상속받는 몇 개의 클래스 (JApplet, JDialog, JFrame 등)
  • JComponent
    • 매우 중요한 추상 클래스
      • 스윙 컴포넌트의 공통적인 속성 구현
      • new JComponent() 인스턴스를 생성할 수 없음
    • AWT 의 Component를 상속받음

컨테이너와 컴포넌트

  • 컨테이너
    • 다른 컴포넌트를 포함할 수 있는 GUI 컴포넌트
    • java.awt.Container : 윈도우 화면 자체가 컨테이너이고 버튼이라고 하는 부품(컴포넌트)이 부착됨
    • 단독으로 존재할 수 있는 컨테이너와 단독으로 존재할 수 없는 컨테이너도 존재
  • 최상위 컨테이너
    • 다른 컨테이너에 속하지 않고 독립적으로 존재 가능한 컨테이너
    • 단독 존재 가능 : 스스로 화면에 자신을 출력하는 컨테이너
      • JFrame, JDialog, JApplet
    • 모든 컨포넌트는 컨테이너에 포함되어야 비로소 화면에 출력 가능
  • 컴포넌트
    • 컨테이너에 포함되어야 비로소 화면에 출력될 수 있는 GUI 객체
    • 모든 GUI 컴포넌트의 최상위 클래스
      • java.awt.Component
    • 스윙 컴포넌트의 최상위 클래스
      • javax.swing.JComponent
  • 최상위 컨테이너에 소속되어야 출력 될 수 있는 객체
    • 컴포넌트 : Jbutton, Jlabel, JTextField, JCheckBox 등

스윙 GUI 프로그램 만들기

    1. 프레임 만들기
    1. 프레임에 스윙 컴포넌트 붙이기
    1. main() 함수 만들기

스윙 프레임 - JFrame

  • 모든 스윙 컴포넌트를 담는 최상위 GUI 컨테이너
    • JFrame을 상속받아 구현
    • 컴포넌트가 화면에 보이려면 스윙 프레임에 부착되어야 함
    • 프레임을 닫으면 프레임 내이 모든 컴포넌트가 보이지 않게 됨.
  • 스윙 프레임(JFrame) 기본 구성
    • 프레임 : 스윙 프로로그램의 기본 틀
    • 메뉴바 : 메뉴들이 부착되는 공간
    • 컨텐트팬 : GUI 컴포넌트들이 부착되는 공간

예제 9-1 : 300x300 크기의 스윙 프레임 만들기

import javax.swing.*;

public class MyFrame extends JFrame {

	public MyFrame() {
		setTitle("300x300 스윙 프레임 만들기");
		setSize(300,300);  //프레임 크기 300x300
		setVisible(true);  //프레임 출력
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		MyFrame frame = new MyFrame();
	}

}


main() 위치

  • 예제 9-1 처럼 프레임을 만드는 클래스 내의 멤버로 메인문을 작성하는것이 더 권장된다

프레임에 컴포넌트 붙이기

  • 타이틀 : 타이틀 바에 부착
public MyFrame() { //생성자
   super("타이틀 문자열");  // 방법 1 : JFrame 의 생성자 호출하여 타이틀 닫기
   setTitle("타이틀 문자열");  // 방법 2: 메소드를 호출하여 타이틀 닫기
}
  • 컨탠트팬 얻기 : 윈도우 화면(패널)에 대한 접근
//프레임의 컨텐트팬을 알아낸다: 컴퓨터가 생성한 기본 프레임에 컴포넌트를 달기 위함!
Container contentPane = frame.getContentPane();
Container contentPane = getContentPane(); 

//이 둘의 차이점
//첫번째 코드는 frame 이라는 JFrame 객체를 사용하여 컨텐트 팬을 얻는 방법
//두번쨰 코드는 현재 클래스의 인스턴스 메소드인 getContentPane() 메소드를 직접 호출
//   - 이 코드가 작성된 위치가 JFrame 하위 클래스 내부인 경우에 주로 사용됨
  • FlowLayout : 적당한 위치에 하나씩 배치시켜줌 -> awt 패키지에 구현되어있음

  • 컨텐트팬에 컴포넌트 부착하기

Container c = frame.getContentPane();  //컨탠트팬 c 를 얻어오고
JButton b = new JButton("Click");  //버튼을 생성
c.add(b);  //참조변수를 add 하여 컨텐트 팬에 버튼을 추가!
  • 컨텐트팬 변경
JPanel p = new JPanel();  //프레임에 부착할 수 있는 패널은 여러 개 가능
frame.setContentPane(p);  //따라서, 해당 프레임에 다른 패널을 추가로 생성해서 부착한 것과 유사한 의미!

예제 9-2 : 3개의 버튼 컴포넌트를 가진 스윙 프레임 만들기

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

public class ContentPaneEx extends JFrame {
	ContentPaneEx(){
		setTitle("ContentPane 과 JFrame");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //x 버튼을 누르면 화면에서 지워지는것에 추가로
        										 		//시스템에서 프로그램이 종료되도록
                                                        //설정하느 코드
		
		Container contentPane = getContentPane(); //컨텐트 팬 가져오기
		contentPane.setBackground(Color.ORANGE);
		contentPane.setLayout(new FlowLayout()); //버튼 위치를 지정하는 레이아웃
		contentPane.add(new JButton("OK"));
		contentPane.add(new JButton("Cancel"));
		contentPane.add(new JButton("Ignore"));
		
		setSize(350, 150);
		setVisible(true);
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new ContentPaneEx();
        //현재 프레임에는 컨텐트 팬이 하나이기 때문에
        //ContentPaneEx ref = new ContentPaneEx() 
        //로 수행하지 않아도 됨
      	// -> (참조변수를 활용하여 수행할 내용이 없음)
	}

}


스윙 응용 프로그램의 종료

  • 응용 프로그램 내에서 스스로 종료
System.exit(0);  //언제 어디서나 무조건 종료
  • 프레임 종료버튼(X) 클릭 시 프레임을 종료하여 프레임 윈도우가 닫힘
    • 프레임이 화면에서 보이지 않게 되고 응용프로그램이 사라짐
      • -> 프레임만 사라진 것이지 main() 프로그램이 종료한 것은 아니다!
      • -> 프로그램이 종료가 되도록 하는 추가 메소드 필요
  • _ 버튼 : 프레임이 사라지지만 응용프로그램은 종료되지 않음
    • 키보드나 마우스 입력을 받지 못함
    • 다시 show() 를 호출하면 보이게 되고작동함
  • 프레임 종료버튼(X) 이 클릭될 때, 프레임과 함께 응용프로그램이 종료되도록 하는 방법 : 다음 코드 추가
// ** 중요 **
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

main() 종료 뒤에도 프레임이 살아 있는 이유?

  • 스윙 프로그램이 실행되는 동안 생성되는 스레드
    • 메인 스레드
      • main() 을 실행하는 스레드
      • 자바 응용프로그램의 실행을 시작한 스레드
    • 이벤트 분배 스레드
      • 스윙 응용프로그램이 실행도리 때 자동으로 실행되는 스레드
      • 이벤트 분배 스레드의 역할
        • 프레임과 버튼 등 GUI 화면 그리기
        • 키나 마우스 입력을 받아 이벤트를 처리할 코드 호출
  • 자바 응용 프로그램의 종료 조건
    • 실행 중인 사용자 스레드가 하나도 없을 떄 종료
  • 스윙 프로그램 main() 종료 뒤 프레임이 살아있는 이유
    • 메인 스레드가 종료되어도 이벤트 분배 스레드가 살아 있다면 프레임 화면에서 마우스나 키 입력을 받을 수 있기 때문
    • 따라서, 메인 스레드 뿐만 아니라 이벤트 분배 스레드도 종료되도록 해야 완벽하게 프로그램이 종료된다.
  • CPU 한테 단독으로 스레드들을 하나씩 순차적으로 제공할 수 있지만 CPU 가 여러개로 병렬처리로 해결이 가능하다.
  • 스레드에 대한 간략한 정보만 소개함.

컨테이너와 배치의 개념

  1. 컨테이너마다 하나의 배치관리자가 존재하며,
    삽입되는 모든 컴포넌트의 위치와 크기를 결정하고 적절히 배치한다.

  2. 컨테이너의 크기가 변하면 내부 컴포넌트들의 위치와 크기를 모두 재절하고 재배치한다.

배치 관리자 대표 유형 4가지

  • java.awt 패키지에 구현되어 있음 : FlowLayout, BorderLayout, GridLayout, CardLayout

컨테이너와 배치관리자

  • 컨테이너의 디폴드 배치 관리자
    • 컨테이너는 생성시 디폴트 배치 관리자 설정
  • 디폴트 배치관리자를 사용하지 않을거면 setLayout로 배치관리자 지정가능
    • Container.setLayout(LayoutManager lm)
      • lm 을 Container의 새로운 배치 관리자로 설정
      //JPanel 패널에 BorderLayout
       //배치 관리자를 설정하는 예
       JPanel p = new JPanel();
       p.setLayout(new BorderLayout());
       
       //컨텐트팬의 배치 관리자를 FlowLayout 으로 변경
       Container c = frame.getContentPane();  //프레임의 컨텐트팬
       c.setLayout(new FlowLayout());  //컨텐트팬에 FlowLayout 변경

FlowLayout

  • 배치 방법
    • 컨테이너 공간 내에 왼쪽에서 오른쪽으로 배치하다가 아래로 내려가서 다시 왼쪽에서 오른쪽으로 배치
      container.setLayout(new FLowLayout());
       container.add(new JButton("add"));
       container.add(new JButton("mul"));   
       ...

FlawLayout : 실행 후 컨텐이너 크기 변경

  • 컨테이너의 크기가 변하면 배치 관리자에 의해 자동으로 재배치됨
  • 따라서, 프레임의 크기를 바꾸면 배치도 변한다.

FLowLayout - 생성자와 속성

  • 생성자 (정렬과 관련한 생성자)
    • FlowLayout()
    • FlowLayout(int align)
    • FlowLayout(int align, int hGap, int vGap)
      • align : 컴포넌트의 정렬(5가지중 가장 많이 사용되는 3가지)
        • FlowLayout.LEFT, FlowLayout.RIGHT, FlowLayout.CENTER(디폴트)
      • hGap : 좌우 두 컴포넌트 사이의 수평 간격, 픽셀 단위(디폴트 5)
      • vGap : 상하 두 컴포넌트 사이의 수직 간격, 픽셀 단위(디폴트 5)

에제 9-3 : FlowLayout 배치 관리자 활용 : LEFT 로 정렬되는 수평 간격이 30 픽셀, 수직 간격이 40 픽셀인 FlowLayout 사용 예

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

public class FlowLayoutEx extends JFrame {
	FlowLayoutEx(){
		setTitle("FlowLayout Sample");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		
        //FlowLayout.LEFT 로 정렬, hGap : 30픽셀, vGap : 40픽셀
		c.setLayout(new FlowLayout(FlowLayout.LEFT, 30, 40));
		c.add(new JButton("add"));
		c.add(new JButton("sub"));
		c.add(new JButton("mul"));
		c.add(new JButton("div"));
		c.add(new JButton("Calculate"));
		
		setSize(350, 250);
		setVisible(true);
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new FlowLayoutEx();
	}

}

BorderLayout

  • 생성자
  • 배치 방법
    • 컨테이너 공간을 5 구역으로 분할, 배치
      • East, West, South, North, Center
    • 배치 방법
      • add(Component comp, int index)
        • comp 를 index 의 공간에 배치
    • 컨텐이너 크기가 변하면 재배치
      container.setLayout(new BorderLayout());
       container.add(new JButton("div"), BoerderLayout.WEST);
       container.add(new JButton("Calculate"), BoerderLayout.CENTER);


예제 9-4 : BorderLayout 배치관리자를 사용하는 예

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

public class BorderLayoutEx extends JFrame {
	BorderLayoutEx(){
		setTitle("BorderLayout Sample");  //프레임의 타이틀 달기
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //프레임 윈도우를 닫으면 프로그램 종료
		Container c = getContentPane(); //컨텐트팬 얻어오기
		c.setLayout(new BorderLayout(30,20)); //컨텐트팬에 BorderLayout 배치관리자 설정
		
        //컴포넌트 추가
		c.add(new JButton("Calculate"), BorderLayout.CENTER);
		c.add(new JButton("add"), BorderLayout.NORTH);
		c.add(new JButton("sub"), BorderLayout.SOUTH);
		c.add(new JButton("mul"), BorderLayout.EAST);
		c.add(new JButton("div"), BorderLayout.WEST);
				
		setSize(300, 200); //프레임 크기 300x200 설정
		setVisible(true);  //프레임을 화면에 출력		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new BorderLayoutEx();
	}
}


GridLayout

  • 생성자
    • GridLayout()
    • GridLayout(int rows, int cols)
    • GridLayout(int rows, int cols, int hGap, int vGap)
      • rows : 격자 행 수 (디폴트 1)
      • cols : 격자의 열 수 (디폴트 1)
      • hGap : 좌우 두 컴포넌트 사이의 수평 간격, 픽셀 단위 (디폴트 0)
      • vGap : 상하 두 컴포넌트 사이의 수직 간격, 픽셀 단위(디폴트 0)
      • rows x cols 만큼의 셀을 가진 격자로 컨테이너 공간을 분할, 배치
  • 배치 방법
    • 컨테이너 공간을 동일한 사각형 격자(그리드)로 분할하고 각 셀에 하나의 컴포넌트 배치
      • 격자 구성은 생성자에서 행수와 열수로 지정
      • 셀에 왼쪽에서 오른쪽으로, 다시 위에서 아래로 순서대로 배치
        //4 x 3 그리드 분할로 컴포넌트 배치
         //수평간격 hGap : 5픽셀, 수직간격 vGap : 5픽셀
         container.setLayout(new GridLayout(4,3,5,5));
         //상단 왼쪽 첫 번째 셀에 버튼 배치
         container.add(new JButtom("1"));
         container.add(new JButtom("2")); //그 옆 셀에 버튼 배치
         ...

예제 9-5 : GridLayout 으로 입력 폼 만들기

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

public class GridLayoutEx extends JFrame {
	GridLayoutEx(){
		setTitle("GridLayout Sample");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		GridLayout grid = new GridLayout(4,2);
		grid.setVgap(5);
		setLayout(grid);
		add(new JLabel("이름"));
		add(new JTextField(""));
		add(new JLabel("학번"));
		add(new JTextField(""));
		add(new JLabel("학과"));
		add(new JTextField(""));
		add(new JLabel("과목"));
		add(new JTextField(""));
		
		setSize(300, 200);
		setVisible(true);
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new GridLayoutEx();
	}
}
  • 두 행 사이의 수직 간격 Vgap 5 픽셀로 설정됨

배치 관리자 없는 컨테이너

  • 개념
    • 응용프로그램에서 컴포넌트의 절대 크기와 절대 위치를 스스로 결정
    • Container.setLayout(null) 로 설정해놓고 우리가 위치 정보를 다음과은 setSize, setLocation, setBounds 등으로 설정한다.
  • 용도
    • 컴포넌트의 크기나 위치를 개발자 임의로 결정하고자 하는 경우
    • 게임 프로그램과 같이 시간이나 마우스/키보드 입력에 따라 컴포넌트들의 위치와 크기가 수시로 변하는 경우
    • 여러 컴포넌트들이 서로 겹치는 효과를 연출하고자 하는 경우
  • 컨테이너 배치 관리자 제거 방법
    • Container.setLayout(null);
      //JPanel 에 배치관리자를 삭제하는 예
       JPanel p = new JPanel();
       p.setLayout(null);
  • 컴포넌트의 크기와 위치 설정
    • 프로그램 내에서 이루어져야함.
    • 컴포넌트들이 서로 겹치는 효과 연출 가능
    • 다음 메소드 이용
      • 컴포넌트 크기 설정 : Component.setSize(int width, int height);
      • 컴포넌트 위치 설정 : Component.setLocation(int x, int y);
      • 컴포넌트 위치와 크기 동시 설정 : Component.setBounds(int x, int y, int width, int height);

예제 9-6 : 배치관리자 없는 컨테이너에 컴포넌트 절대 위치와 크기로 지정

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

public class NullContainerEx extends JFrame {
	NullContainerEx(){
		setTitle("Null Container Sample");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Container c = getContentPane();
		c.setLayout(null);
		
		JLabel la = new JLabel("Hello, Press Buttons!");
		la.setLocation(130, 50); //la 는 130, 50 위치에 hello~ 내보내짐
		la.setSize(200, 20);
		c.add(la);
        //for 문을 사용하여 9개의 버튼(사이즈는 똑같음) 생성
		for(int i=1; i<=9; i++) { //증가하면서 해당하는 위치에 등록
            //i 를 문자열로 바꿔라 라는 메소드
			JButton b = new JButton(Integer.toString(i)); //버튼 생성!
			b.setLocation(i*15, i*15);
			b.setSize(50,20);
			c.add(b);
		}
		
		setSize(300, 200);
		setVisible(true);
		
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new NullContainerEx();
	}

}
// 원하는 위치에 원하는 크기로 컴포넌트를 마음대로 배치


profile
공부한 것 기록용

0개의 댓글