04. 컴포넌트 배치
컨테이너는 컴포넌트(버튼, 체크박스 등)를 배치할 때 배치 관리자(Layout Manager)를 사용합니다. 배치 관리자를 사용하면 컨테이너의 크기가 변경되더라도 컴포넌트의 크기나 위치가 유동적으로 조절되어 레이아웃을 유지할 수 있습니다.
물론 크기가 고정된 컨테이너의 경우, 좌표값(x, y)을 직접 지정하여 배치할 수도 있습니다(NullLayout).
💡 그림으로 이해하기: 배치 관리자 역할 (가구 배치와 인테리어 디자이너)
배치 관리자의 개념을 쉽게 이해하기 위해 실생활에 비유해 볼까요?
- 컨테이너는 우리가 꾸밀 ‘빈 방’입니다.
- 컴포넌트는 방 안에 들어갈 ‘침대, 책상, 서랍장 같은 가구’들입니다.
- 배치 관리자는 이 가구들을 방 크기에 맞게 자동으로 배치해 주는 ‘인테리어 디자이너(또는 공간 정리 전문가)’입니다!
방의 크기(윈도우 크기)가 늘어나거나 줄어들어도, 인테리어 디자이너(배치 관리자)가 미리 정해진 규칙에 따라 가구들의 간격과 크기를 자동으로 보기 좋게 조절해 줍니다. 반면에 배치 관리자를 쓰지 않고 좌표로 직접 배치하는 것(NullLayout)은 가구를 바닥에 못으로 박아 고정하는 것과 같습니다. 방이 넓어져도 가구는 그대로 구석에 박혀 있게 되죠!

| 배치 관리자 | 설명 |
|---|---|
| BorderLayout | 동·서·남·북·중앙(Center) 5개 영역으로 나누어 배치. (JFrame, JDialog, JWindow 기본) |
| FlowLayout | 왼쪽에서 오른쪽으로 물 흐르듯 배치. 공간이 부족하면 아래로 줄바꿈. (JPanel 기본) |
| GridLayout | 행(Row)과 열(Column)의 격자(Grid)에 균등한 크기로 배치. |
| CardLayout | 여러 컴포넌트(패널)를 포개 놓고, 한 번에 하나씩 보여주는 배치 (탭과 유사). |
| GridBagLayout | 격자 기반이지만, 컴포넌트의 크기나 위치를 매우 세밀하게 제어 가능 (복잡함). |
| NullLayout | 배치 관리자 없이 좌표값(setBounds)으로 직접 배치. |
setLayout() 메서드로 컨테이너의 배치 관리자를 변경할 수 있습니다.
jFrame.getContentPane().setLayout(new FlowLayout());
1. BorderLayout
BorderLayout은 컨테이너를 North, South, East, West, Center의 5개 영역으로 나눕니다.
- North/South: 컴포넌트의 높이는 유지되고, 폭은 컨테이너에 맞춰집니다.
- East/West: 컴포넌트의 폭은 유지되고, 높이는 컨테이너에 맞춰집니다.
-
Center: 남은 모든 공간을 차지합니다.
- 실습 예제 파일: BorderLayoutExample.java (경로:
sample/sec04/exam01_borderlayout/BorderLayoutExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam01_borderlayout/BorderLayoutExample.java # 2. 실행 java -cp sample sec04.exam01_borderlayout.BorderLayoutExample -
실행 결과 화면:

package sec04.exam01_borderlayout;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class BorderLayoutExample extends JFrame {
private JTextField txtNorth;
private JTextArea txtCenter;
private JButton btnSouth;
public BorderLayoutExample() {
this.setTitle("BorderLayoutExample");
this.setSize(300, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 북쪽, 중앙, 남쪽에 컴포넌트 배치
this.getContentPane().add(getTxtNorth(), BorderLayout.NORTH);
this.getContentPane().add(getTxtCenter(), BorderLayout.CENTER);
this.getContentPane().add(getBtnSouth(), BorderLayout.SOUTH);
}
private JTextField getTxtNorth() {
if (txtNorth == null) {
txtNorth = new JTextField();
txtNorth.setText("북쪽 컴포넌트");
txtNorth.setBackground(Color.YELLOW);
}
return txtNorth;
}
private JTextArea getTxtCenter() {
if (txtCenter == null) {
txtCenter = new JTextArea();
txtCenter.append("중앙 컴포넌트\n");
txtCenter.append("동쪽/서쪽이 없으면 중앙이 확장됩니다.\n");
}
return txtCenter;
}
private JButton getBtnSouth() {
if (btnSouth == null) {
btnSouth = new JButton("남쪽 컴포넌트");
}
return btnSouth;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
BorderLayoutExample jFrame = new BorderLayoutExample();
jFrame.setVisible(true);
});
}
}
2. FlowLayout
FlowLayout은 컴포넌트를 왼쪽에서 오른쪽으로 차례대로 배치합니다. 한 줄이 꽉 차면 다음 줄로 넘어갑니다. 컴포넌트의 크기는 각 컴포넌트의 적정 크기(Preferred Size)로 유지됩니다.
- 실습 예제 파일: FlowLayoutExample.java (경로:
sample/sec04/exam02_flowlayout/FlowLayoutExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam02_flowlayout/FlowLayoutExample.java # 2. 실행 java -cp sample sec04.exam02_flowlayout.FlowLayoutExample -
실행 결과 화면:

package sec04.exam02_flowlayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class FlowLayoutExample extends JFrame {
private JButton btnOk;
private JButton btnCancel;
public FlowLayoutExample() {
this.setTitle("FlowLayoutExample");
this.setSize(300, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// FlowLayout 설정
this.setLayout(new FlowLayout());
this.getContentPane().add(getBtnOk());
this.getContentPane().add(getBtnCancel());
}
private JButton getBtnOk() {
if(btnOk == null) {
btnOk = new JButton("확인");
}
return btnOk;
}
private JButton getBtnCancel() {
if(btnCancel == null) {
btnCancel = new JButton("취소");
}
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
FlowLayoutExample jFrame = new FlowLayoutExample();
jFrame.setVisible(true);
});
}
}
JPanel과 Layout
JPanel은 기본적으로 FlowLayout을 사용합니다. 복잡한 배치를 할 때 JFrame(BorderLayout)의 각 영역에 JPanel을 배치하고, 그 JPanel 안에 다시 컴포넌트들을 FlowLayout 등으로 배치하는 방식(중첩 레이아웃)을 많이 사용합니다.
- 실습 예제 파일: JPanelExample.java (경로:
sample/sec04/exam03_jpanel/JPanelExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam03_jpanel/JPanelExample.java # 2. 실행 java -cp sample sec04.exam03_jpanel.JPanelExample -
실행 결과 화면:

package sec04.exam03_jpanel;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class JPanelExample extends JFrame {
private JPanel panelSouth;
private JButton btnOk;
private JButton btnCancel;
public JPanelExample() {
this.setTitle("JPanelExample");
this.setSize(250, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// JFrame 남쪽에 JPanel 배치
this.getContentPane().add(getPanelSouth(), BorderLayout.SOUTH);
}
public JPanel getPanelSouth() {
if (panelSouth == null) {
panelSouth = new JPanel(); // 기본 FlowLayout
panelSouth.setBackground(Color.WHITE);
panelSouth.add(getBtnOk());
panelSouth.add(getBtnCancel());
}
return panelSouth;
}
public JButton getBtnOk() {
if (btnOk == null) btnOk = new JButton("확인");
return btnOk;
}
public JButton getBtnCancel() {
if (btnCancel == null) btnCancel = new JButton("취소");
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JPanelExample jFrame = new JPanelExample();
jFrame.setVisible(true);
});
}
}
3. GridLayout
GridLayout은 컨테이너를 행(Row)과 열(Column)로 나누어 모든 구획을 동일한 크기로 만듭니다. 컴포넌트가 추가되면 왼쪽→오른쪽, 위→아래 순서로 채워집니다.
- 실습 예제 파일: GridLayoutExample.java (경로:
sample/sec04/exam04_gridlayout/GridLayoutExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam04_gridlayout/GridLayoutExample.java # 2. 실행 java -cp sample sec04.exam04_gridlayout.GridLayoutExample -
실행 결과 화면:

package sec04.exam04_gridlayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class GridLayoutExample extends JFrame {
private JButton[][] btn;
public GridLayoutExample() {
setTitle("GridLayoutExample");
setSize(300, 100);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 2행 3열 GridLayout
setLayout(new GridLayout(2, 3));
for(int r = 0; r < 2; r++) {
for(int c = 0; c < 3; c++) {
getContentPane().add(getBtn()[r][c]);
}
}
}
public JButton[][] getBtn() {
if(btn == null) {
btn = new JButton[2][3];
for(int r = 0; r < 2; r++) {
for(int c = 0; c < 3; c++) {
btn[r][c] = new JButton("["+r+"][" + c + "]");
}
}
}
return btn;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
GridLayoutExample jFrame = new GridLayoutExample();
jFrame.setVisible(true);
});
}
}
4. CardLayout
CardLayout은 여러 컴포넌트(주로 패널)를 같은 위치에 겹쳐 놓고, 한 번에 하나만 보여줍니다. first(), last(), next(), show() 메서드로 보여줄 카드를 전환합니다.
- 실습 예제 파일: CardLayoutExample.java (경로:
sample/sec04/exam05_cardlayout/CardLayoutExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam05_cardlayout/CardLayoutExample.java # 2. 실행 (실행 시 1초 간격으로 카드 컬러 패널이 순차 전환됩니다) java -cp sample sec04.exam05_cardlayout.CardLayoutExample -
실행 결과 화면:

package sec04.exam05_cardlayout;
import java.awt.CardLayout;
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class CardLayoutExample extends JFrame {
private JPanel redCard, greenCard, blueCard;
public CardLayoutExample() {
this.setTitle("CardLayoutExample");
this.setSize(250, 400);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// CardLayout 설정
this.getContentPane().setLayout(new CardLayout());
// 이름과 함께 패널 추가
this.getContentPane().add("RedCard", getRedCard());
this.getContentPane().add("GreenCard", getGreenCard());
this.getContentPane().add("BlueCard", getBlueCard());
}
public JPanel getRedCard() {
if (redCard == null) {
redCard = new JPanel();
redCard.setBackground(Color.RED);
}
return redCard;
}
public JPanel getGreenCard() {
if (greenCard == null) {
greenCard = new JPanel();
greenCard.setBackground(Color.GREEN);
}
return greenCard;
}
public JPanel getBlueCard() {
if (blueCard == null) {
blueCard = new JPanel();
blueCard.setBackground(Color.BLUE);
}
return blueCard;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
final CardLayoutExample jFrame = new CardLayoutExample();
jFrame.setVisible(true);
// 1초마다 자동으로 카드 전환하는 스레드
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
SwingUtilities.invokeLater(() -> {
CardLayout cardLayout = (CardLayout) jFrame.getContentPane().getLayout();
cardLayout.next(jFrame.getContentPane());
});
}
}).start();
});
}
}
5. NullLayout (절대 위치)
배치 관리자를 null로 설정하고, setBounds(x, y, width, height)를 사용하여 컴포넌트의 위치와 크기를 픽셀 단위로 직접 지정합니다. 컨테이너 크기가 변해도 컴포넌트 위치가 변하지 않습니다.
- 실습 예제 파일: NullLayoutExample.java (경로:
sample/sec04/exam06_nulllayout/NullLayoutExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam06_nulllayout/NullLayoutExample.java # 2. 실행 java -cp sample sec04.exam06_nulllayout.NullLayoutExample -
실행 결과 화면:

package sec04.exam06_nulllayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class NullLayoutExample extends JFrame {
private JButton btnOk;
public NullLayoutExample() {
this.setTitle("NullLayoutExample");
this.setSize(300, 200);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// NullLayout 설정
this.getContentPane().setLayout(null);
this.getContentPane().add(getBtnOk());
}
public JButton getBtnOk() {
if(btnOk == null) {
btnOk = new JButton("확인");
// 절대 위치 및 크기 설정
btnOk.setBounds(100, 50, 70, 60);
}
return btnOk;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
NullLayoutExample jFrame = new NullLayoutExample();
jFrame.setVisible(true);
});
}
}
6. Pack
pack() 메서드는 컨테이너 내부의 컴포넌트들이 선호하는 크기(Preferred Size)에 맞춰서 컨테이너(윈도우)의 크기를 자동으로 조절해줍니다. setSize() 대신 사용하면 내용물에 딱 맞는 윈도우 크기를 얻을 수 있습니다.
- 실습 예제 파일: PackExample.java (경로:
sample/sec04/exam07_pack/PackExample.java) - 실행 방법:
# 1. 04_component_layout 디렉토리로 이동 후 컴파일 javac -d sample sample/sec04/exam07_pack/PackExample.java # 2. 실행 java -cp sample sec04.exam07_pack.PackExample -
실행 결과 화면:

package sec04.exam07_pack;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class PackExample extends JFrame {
private JButton btnOk;
private JButton btnCancel;
public PackExample() {
this.setTitle("PackExample");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(new FlowLayout());
this.getContentPane().add(getBtnOk());
this.getContentPane().add(getBtnCancel());
// 내부 컴포넌트 크기에 맞게 윈도우 크기 자동 조절
this.pack();
}
private JButton getBtnOk() {
if(btnOk == null) {
btnOk = new JButton("확인");
}
return btnOk;
}
private JButton getBtnCancel() {
if(btnCancel == null) {
btnCancel = new JButton("취소");
}
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
PackExample jFrame = new PackExample();
jFrame.setVisible(true);
});
}
}