Java GUI 기초 - Swing

1. 자바의 GUI


GUI란 Graphical User Interface의 약자로 이미지 혹은 그래픽을 이용하여 메뉴 등을 포함하는 화면을 구성하고, 키보드 외 마우스 등의 편리한 입력 도구를 이용하여 사용자가 입력하기 편하도록 만들어진 사용자 인터페이스이다. 자바는 GUI 응용프로그램을 쉽게 작성할 수 있도록 다양한 GUI 컴포넌트를 제공한다. AWT 컴포넌트와 Swing 컴포넌트로 구분되며, 각각 jawa.awt 패키지와 javax.swing 패키지를 통해 공급된다.

Swing

AWT보다는 Swing사용이 권장된다. Swing은 운영체제의 도움을 받지 않기 때문에 경량 컴포넌트라고 불리고 순수 자바 언어로 작성되었다. 스윙 컴포넌트의 이름은 AWT 컴포넌트와 구분하기 위해서 모두 대문자 J로 시작한다. 스윙은 AWT에 구현된 이벤트 처리나 GUI 컴포넌트의 기본 원리를 바탕으로 작성되었기 때문에, 스윙을 사용하기 위해 AWT 패키지가 필요하다. 하지만 내부 구조는 서로 다르기에 컴포넌트를 혼용해서 사용하면 안된다. 예를 들면, JButton과 Button을 동시에 사용해서는 안된다.


2. 자바 GUI 패키지 계층 구조


모든 GUI 컴포넌트들은 Component 클래스를 반드시 상속받는다. AWT는 Component를 직접 상속 받는 것들과 Component를 상속받은 Container을 상속받는 것들이 있다. Swing 클래스는 JApplet, JFrame, JDialog를 제외한 것들은 Container을 상속받은 JComponent를 상속받는다.

  • 컨테이너: 다른 GUI 컴포넌트를 포함할 수 있는 컴포넌트이다. 그러므로 컨테이너는 컴포넌트이면서 동시에 컨테이너다.
  • 컴포넌트 : 컨테이너와 달리 다른 컴포넌트를 포함할 수 없으며, 컨테이너에 포함되어야 비로소 화면에 출력될 수 있는 GUI 객체, 기본적으로 java.awt.Component를 상속받기 때문에, Component 클래스에는 모든 컴포넌트들의 공통적인 속성과 기능이 작성되어 있다.
  • 최상위 컨테이너 : 다른 컨테이너에 속하지 않고 독립적으로 화면에 출력될 수 있는 컨테이너, JFrame, JDialog, JApplet이 이에 속한다. 다른 컨테이너나 컴포넌트들은 다른 컨테이너에 부착되고 마지막에는 최상위 컨테이너에 부착되어야만 화면에 출력된다.
  • 자식 컴포넌트 : 컨테이너와 컴포넌트 계층 구조로 구성되어, 컨테이너에 부착된 컴포넌트들


3. 스윙 GUI 프로그램 만들기


스윙으로 GUI 응용프로그램을 만들기 위해서는 다음 세 과정이 필요하다.

  • 스윙 프레임 작성
  • main 메서드 작성
  • 프레임에 스윙 컴포넌트 붙이기

스윙 패키지 사용을 위한 import문

import java.awt.*; // 폰트 등 그래픽 처리를 위한 클래스들의 경로명
import java.awt.event.*; // 이벤트 처리에 필요한 기본 클래스들의 경로명
import java.swing.*; // 스윙 컴포넌트 클래스들의 경로명
import javax.swing.event.*; // 스윙 이벤트 처리에 필요한 클래스들의 경로명


스윙 프레임과 컨텐트팬

스윙 프레임은 모든 스윙 컴포넌트들을 담는 최상위 컨테이너이다. 스윙 프레임이 출력될 때, 스윙 프레임 내에 부착된 모든 컴포넌트들이 화면에 출력된다. 컴포넌트들은 스윙 프레임 없이 독립적으로 화면에 출력될 수 없다. 스윙에서 프레임의 역할을 수행하는 클래스가 JFrame이다. JFrame은 Frame, 메뉴바, 컨텐트팬으로 구성된다. 메뉴바는 메뉴들을 부착, 컨텐트팬은 메뉴를 제외한 모든 GUI 컴포넌트들을 부착하는 공간이다. 참고로 컨텐트팬은 컨테이너 타입이다.


프레임 만들기와 main의 위치

그림1

package guiTest;

import javax.swing.JFrame;

public class MyFrame extends JFrame{
	public MyFrame() {
        // 아래 set들은 모두 JFrame의 멤버들
		setTitle("350*350 스윙 프레임 만들기"); // 창 타이틀 명
		setSize(300,300); // 크기 -> 기본 0 * 0
		setVisible(true);// 기본값이 invisible이므로 보이게 하려면 visible true해줘야한다.
	}
	

	public static void main(String[] args) {
		MyFrame frame = new MyFrame();		
	}

}

응용 프로그램에서 main의 기능을 최소화하는 것이 좋다. 따라서 main에는 스윙 응용프르고램이 실행되는 시작점으로서 프레임을 생성하는 코드 정도만 만들고, 나머지 기능은 프레임 클래스에 작성하는 것이 좋다. 위와 같이 main 메서드를 MyFrame 클래스에 두거나, 메인 메서드만 가진 클래스를 따로 만들어 줘도 되는데 굳이 따로 만들 필요는 없다.

컴포넌트 붙이기

응용프로그램 구성의 바탕이 되는 프레임 틀을 만들었으니 컴포넌트를 붙여보자. JPanel을 상속받은 판넬을 하나 만들어서 프레임에 붙여보았다.

// 객체 지향적으로 만들기
public class ContentPaneEx extends JPanel{
	
	public ContentPaneEx() {
		setBackground(Color.ORANGE);
		setLayout(new FlowLayout());
		
		add(new JButton("ok"));
		add(new JButton("cancel"));
		add(new JButton("ignore"));
	}

}

public class MyFrame extends JFrame{
	public MyFrame() {		
		setTitle("350*350 스윙 프레임 만들기");
        // super("타이틀문자열") 도 가능
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		setContentPane(new ContentPaneEx());
		
		setSize(300,300);
		setVisible(true);		
	}
	

	public static void main(String[] args) {
		MyFrame frame = new MyFrame();		
	}

}

// 깡으로 만들기

public class MyFrame extends JFrame{
	public MyFrame() {		
		setTitle("350*350 스윙 프레임 만들기");
        // 프레임 윈도우 닫으면 프로그램 종료하도록 설정
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Container contentPane = getContentPane(); // 컨텐트 팬 알아내기
		contentPane.setBackground(Color.orange); // 컨텐트 팬 색 지정
		contentPane.setLayout(new FlowLayout()); // 컨텐트팬에 배치 관리자 달기
		
		contentPane.add(new JButton("Ok"));
		contentPane.add(new JButton("hello"));
		contentPane.add(new JButton("world"));
		
		
		setSize(300,300); // 프레임 크기 설정
		setVisible(true); // 프레임 화면에 출력
	}
	

	public static void main(String[] args) {
		MyFrame frame = new MyFrame();		
	}

}

  • 타이틀 달기
    • setTitle(“타이틀문자열”)
    • super(“타이틀문자열”) 둘중 하나 선택
  • 컴텐트팬 변경
    • 객체지향적으로 설계 시에는 컨텐트팬을 갈아껴줘야한다. JFrame의 setContentPane 메서드로 현재 프레임의 컨텐트팬을 갈아낄 수 있다.
  • 컨텐트팬에 컴포넌트 달기
    • 기본적으로 JFrame 객체가 생길 때 컨텐트팬이 자동으로 생성된다. 현재 프레임에 붙어 있는 컨텐트팬을 알아내기 위해서는 JFrame 클래스의 getContentPane() 메서드를 호출해야 한다. 컨텐트 팬은 Container 타입이다.
    • 컨텐트팬은 컨테이너이기 때문에 add메서드로 컴포넌트를 부착할 수 있다.
  • 프레임 윈도우의 오른쪽 상단에 있는 X표시는 프레임 윈도우를 닫는 버튼이지 프로그램을 종료시키는 버튼이 아니다. 사용자의 눈에는 보이지 않지만 프로그래ㅑㅁ을 계속 실행중인 것이다. 따라서 위에 exit_on_close로 프레임 윈도우가 닫히면 프로그램도 같이 종료되게 코딩할 수 있다.


4. 컨테이너와 배치


컨테이너에 부착되는 컴포넌트들의 위치와 크기는 컨테이너 내부에 있는 배치관리자에 의해 결정된다. 컨테이너마다 하나의 배치 관리자가 있으며, 배치 관리자는 컨테이너에 컴포넌트가 부착되는 시점에 컴포넌트의 위치와 크기를 결정한다. 대표적인 배치 관리자의 종류는 4가지고 다음과 같다.

  • FlowLayout : 컨테이너에 부착되는 순서대로 왼쪽에서 오른쪽으로 꽉차면 아래로 내려와 다시 왼쪽에서 오른쪽으로 컴포넌트를 배치, 컴포넌트의 크기는 화면에 출력될 수 있는 적당한 크기로 설정, 컨테이너 크기가 변하면 그에 맞도록 재배치
  • BorderLayout : 컨테이너 공간을 east, west, south, north, center의 5개 영역으로 나누고 응용프로그램에서 지정한 영역에 컴포넌트를 배치, 지정하지 않으면 중앙에 배치되고, 크기는 영역의 크기에 맞추어 설정, 컨테이너의 크기가 변하면 재배치
  • GridLayout : 컨테이너 공간을 응용프로그램에서 설정한 동일한 크기의 2차원 격자로 나누고 컴포넌트가 삽입되는 순서대로 좌에서 우, 다시 위에서 아래로 배치한다. 컴포넌트의 크기는 셀의 크기와 동일
  • CardLayout : 카드를 쌓아 놓은 듯 컴포넌트를 포개어 배치, 컴포넌트의 크기는 컨테이너의 크기와 동일하게 설정

컨테이너가 생성될 때 자동으로 디폴트 배치관리자가 생성되는데 다음과 같다.

  • window, JWindow : BorderLayout
  • Frame,JFrame : BorderLayout
  • Dialog, JDialog : BorderLayout
  • Panel, JPanel : FlowLayout
  • Applet, JApplet : FlowLayout

배치 관리자 설정은 setLayout메서드를 사용하면 된다.

JPanel p = new JPanel();
p.setLayout(new BorderLayout()); 

FlowLayout

// 생성자 오버로딩
FlowLayout()
FlowLayout(int align)
FlowLayout(int align, int hGap, int vGap)

new FlowLayout(FlowLayout.LEFT,10,20)
  • align : 컴포넌트 정렬 방법, LEFT, RIGHT, CENTER(디폴트)
  • hGap : 좌우 컴포넌트 사이의 수평 간격, 픽셀 단위, 디폴트 5
  • vGap : 상하 컴포넌트 사이의 수직 간격, 픽셀 단위, 디폴트 5


BorderLayout

컨테이너에 컴포넌트를 삽입하기 위해서는 add 메서드에 컴포넌트의 위치(CENTER, NORTH, WEST, SOUTH, EAST)를 지정해줘야 한다. 컨테이너의 크기가 변하면 컴포넌트의 크기를 재조정된다. 방향이 5개라 일차적으로 5개의 컴포넌트밖에 붙일 수 없다. 더 붙이려면 다른 컨테이너를 부착하고 그 곳에 컴포넌트를 붙여야 한다. 또한, CENTER에 부착될 때 다른 컴포넌트가 없다면 전체 크기로 배치된다.

// 컴포넌트 붙이기
container.setLayout(new BorderLayout());
container.add(new JButton("div"),BorderLayout.WEST);
container.add(new JButton("time"),BorderLayout.CENTER);

// 생성자 속성
BorderLayout()
BorderLayout(int hGap, int vGap)
  • hGap : 좌우 컴포넌트 사이의 수평 간격, 픽셀 단위, 디폴트 0
  • vGap : 상하 컴포넌트 사이의 수직 간격, 픽셀 단위, 디폴트 0


GridLayout

컨테이너 공간을 그리드 모양으로 분할하여 각 셀에 하나씩 컴포넌트를 배치하는 방법으로 배치순서는 FlowLayout과 같다. 만약 셀 수보다 많은 컴포넌트가 추가되면 생성자에서 주어진 형식이 지켜지지 않고, 모든 컴포넌트를 수용하도록 행과 열의 수가 적당히 변형된다.

// 생성자
GridLayout()
GridLayout(int rows, int cols)
GridLayout(int rows, int cols, int hGap, int vGap)

// 컴포넌트 붙이기
container.setLayout(new GridLayout(4,3)); // 4*3 분할로 컴포넌트 배치 -> 4 * 3 행렬이라고 보면 된다.
container.add(new JButton("1")); // (0,0)
container.add(new JButton("2")); // (0,1)
  • rows : 행수, 디폴트 1
  • cols : 열수, 디폴트 1
  • hGap : 좌우 컴포넌트 사이의 수평 간격, 픽셀 단위, 디폴트 0
  • vGap : 상하 컴포넌트 사이의 수직 간격, 픽셀 단위, 디폴트 0


5. 배치관리자가 없는 컨테이너


모든 컨테이너는 배치관리자를 가지고 컴포넌트의 위치와 크기를 결정한다. 하지만 이런 경우가 불편할 때도 있다. 따라서 제거할 수 있다.

container.setLayout(null); // setLayout의 인자로 null -> 배치 관리자 제거

제거한 이후에는 컴포넌트의 절대 위치와 절태 크기를 지정해줘야 한다. 컴포넌트는 다음과 같은 메서드를 제공한다.

  • void setSize(int width, int height); // 크기 설정
  • void setLopcation(int x, int y); // 위치 설정
  • void setBounds(int x, int y, int width, int height); // 위치 크기 동시 설정
Panel p = new Jpanel();
p.setLayout(null);
Jbutton clickButton = new JButton("Click");
clickButton.setSize(100,40);
clickButton.setLocation(50,50);
p.add(clickButton); // 판넬에 버튼 부착



본 포스팅은 ‘명품 JAVA Programming’를 읽고 공부한 내용을 바탕으로 작성하였습니다.


© 2021. By Backtony