컴포넌트 배치
컨테이너는 기본적으로 배치 관리자로 컴포넌트를 배치한다
- 컨테이너에는 UI 컴포넌트들이 배치된다.
- 대표적인 컴포넌트에는 버튼, 체크박스, 라디오 버튼, 콤 포, 리스트 등이 있다.
- 배치 관리자는 좌표값으로 컴포넌트를 배치하지 않고, 컨테이너를 몇 개의 구획으로 나누어 하나의 구획에 하나의 컴포넌트를 배치해준다
- 배치 관리자로 배치하게 되면 컨테이너의 크기가 사용자에 의해 변경되더라도 컴포넌트의 크기가 비율적으로 늘거나 줄게되어 배치 모양이 그대로 유지된다는 장점이있다.
Layout Manager
컨테이너가 컴포넌트를 배치할 때에는 배치 관리자(Layout Manager)가 무엇이냐에 따라 달라진다.
JWindow, JFrame, JDialog는 기본적으로 BorderLayout 배치 관리자를 사용하고, JPanel은 FlowLayout을 사용한다.
자바는 java.awt 패키지에서 다음과 같은 배치 관리자를 제공한다.
배치 관리자 | 설명 |
BorderLayout | 동·서·남·북·중앙으로 컴포넌트를 배치 |
CardLayout | 여러 장의 카드에 컴포넌트를 각각 배치 |
FlowLayout | 왼쪽에서 오른쪽으로 컴포넌트를 배치 |
GridLayout | 바둑판과 같은 격자에 컴포넌트를 배치 |
GridBagLayout | 바둑판과 같은 격자에 컴포넌트를 배치하지만 격자 간 병합 가능 |
컨테이너의 기본 배치 관리자 대신 다른 것을 사용하고 싶다면 setLayout() 메소드로 변경할 수 있다.
setLayout()의 매개변수 데이터 타입은 LayoutManager 인터페이스인데, 모든 배치 관리자 의 인스턴스가 올 수 있다.
JFrame의 배치 관리자를 변경하는 방법
BorderLayout
BorderLayout 배치 관리자는 컨테이너를 중앙· 동·서·남·북으로 구획 짓고, 각 구획에 하나의 컴포넌트 또는 컨테이너를 배치
일반적으로 각 구획에는 JPanel 컨테이너가 배치되어 복잡한 형태의 UI를 만들어낸다.
JFrame의 각 구획에 JButton 컴포넌트를 배치한 것
jFrame.getContentPane().add(컴포넌트, BorderLayout.CENTER);
jFrame.getContentPane().add(컴포넌트, BorderLayout.EAST);
jFrame.getContentPane().add(컴포넌트, BorderLayout.WEST);
jFrame.getContentPane().add(컴포넌트, BorderLayout.SOUTH);
jFrame.getContentPane().add(컴포넌트, BorderLayout.NORTH);
첫 번째 매개값에는 배치할 컴포넌트 객체가 온다.
두 번째 매개값에는 어떤 구획에 배치할 것인지 지정하는 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);
}
//JTextField 생성
private JTextField getTxtNorth() {
if (txtNorth == null) {
txtNorth = new JTextField();
txtNorth.setText("북쪽 컴포넌트");
txtNorth.setBackground(Color.YELLOW);
}
return txtNorth;
}
//JTextArea 생성
private JTextArea getTxtCenter() {
if (txtCenter == null) {
txtCenter = new JTextArea();
txtCenter.append("중앙 컴포넌트\n");
txtCenter.append("동쪽 컴포넌트가 없으니 동쪽으로 확장\n");
txtCenter.append("서쪽 컴포넌트가 없으니 서쪽으로 확장\n");
}
return txtCenter;
}
//JButton 생성
private JButton getBtnSouth() {
if (btnSouth == null) {
btnSouth = new JButton();
btnSouth.setText("남쪽 컴포넌트");
}
return btnSouth;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
BorderLayoutExample jFrame = new BorderLayoutExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
FlowLayout
FlowLayout 배치 관리자는 이미 배치된 컴포넌트의 오른쪽 옆에 새로운 컴포넌트를 배치
오른쪽에 배치할 공간이 부족하면 하단에 배치하기 때문에 사용자에 의해 컨테이너의 폭(width)이 변경되 면 컴포넌트의 배치 위치가 변경될 수 있다
JFrame의 배치 관리자로 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();
btnOk.setText("확인");
}
return btnOk;
}
//Cancel 버튼 생성
private JButton getBtnCancel() {
if(btnCancel == null) {
btnCancel = new JButton();
btnCancel.setText("취소");
}
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
FlowLayoutExample jFrame = new FlowLayoutExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
JFrame 남쪽에 JPanel을 추가하고, JPanel 내부에 JButton 두 개를 배치
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 FlowLayoutExample extends JFrame {
private JPanel panelSouth;
private JButton btnOk;
private JButton btnCancel;
// 메인 윈도우 설정
public FlowLayoutExample() {
this.setTitle("FlowLayoutExample");
this.setSize(300, 100);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.getContentPane().add(getPanelSouth(), BorderLayout.SOUTH);
}
//JPanel 생성
public JPanel getPanelSouth() {
if (panelSouth == null) {
panelSouth = new JPanel();
panelSouth.add(getBtnOk());
panelSouth.add(getBtnCancel());
}
return panelSouth;
}
private JButton getBtnOk() {
if(btnOk == null) {
btnOk = new JButton();
btnOk.setText("확인");
}
return btnOk;
}
//Cancel 버튼 생성
private JButton getBtnCancel() {
if(btnCancel == null) {
btnCancel = new JButton();
btnCancel.setText("취소");
}
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
FlowLayoutExample jFrame = new FlowLayoutExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
GridLayout
GridLayout 배치 관리자는 컨테이너를 행(row)과 열(column)로 구성된 테이블 모양으로 구획 짓고, 각 구획 에 하나의 컴포넌트를 배치
컴포넌트 배치 순서는 첫 번째 행의 첫 번째 열부터 배치되고, 행의 마지막 열까지 배치가 끝나면 다 음 행의 첫 번째 열부터 다시 차례대로 배치된다.
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);
// 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();
btn[r][c].setText("["+r+"]["+c+"]");
}
}
}
return btn;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
GridLayoutExample jFrame = new GridLayoutExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
크기를 변경할수록 버튼 크기가 바
CardLayout
CardLayout 배치 관리자는 이름에서도 알 수 있듯이 여러 장의 카드를 포개 놓고 한 번에 하나의 카드를 보여주는 역할을 한다. 카드는 하나의 JPanel로 구성된다.
CardLayout 메소드 | 설명 |
first(Container container) | 첫 번째 배치한 카드를 보이게 한다. |
last(Container container) | 마지막에 배치한 카드를 보이게 한다. |
next(Container container) | 현재 카드 다음에 배치한 카드를 보이게 한다. |
show(Container container, String name) | 지정된 이름의 카드를 보이게 한다. |
3개의 색깔 카드를 JFrame에 추가하고 1초 간격으로 카드를 변경 방법
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으로 변경하고 3개의 카드 추가
this.getContentPane().setLayout(new CardLayout());
this.getContentPane().add("RedCard", getRedCard());
this.getContentPane().add("GreenCard", getGreenCard());
this.getContentPane().add("BlueCard", getBlueCard());
}
//RedCard에 해당하는 JPanel 생성
public JPanel getRedCard() {
if (redCard == null) {
redCard = new JPanel();
redCard.setBackground(Color.RED);
}
return redCard;
}
//GreenCard에 해당하는 JPanel 생성
public JPanel getGreenCard() {
if (greenCard == null) {
greenCard = new JPanel();
greenCard.setBackground(Color.GREEN);
}
return greenCard;
}
//BlueCard에 해당하는 JPanel 생성
public JPanel getBlueCard() {
if (blueCard == null) {
blueCard = new JPanel();
blueCard.setBackground(Color.BLUE);
}
return blueCard;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final CardLayoutExample jFrame = new CardLayoutExample();
jFrame.setVisible(true);
//반복 스레드 생성
Thread thread = new Thread() {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
//2초간 일시정지
Thread.sleep(1000);
} catch (InterruptedException e) {
}
//이벤트 큐에 Runnable 객체 넣기
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//CardLayout을 얻어 다음 카드 보여주기
CardLayout cardLayout =
(CardLayout) jFrame.getContentPane().getLayout();
cardLayout.next(jFrame.getContentPane());
}
});
}
}
};
//반복 스레드 시작
thread.start();
}
});
}
}
- 실행 결과 -
반
NullLayout
NullLayout은 컨테이너의 setLayout() 메소드에 배치 관리자 대신 매개값을 null로 설정한 것을 말한다.
어떠한 배치 관리자도 사용하지 않고 좌표값으로 컴포넌트를 배치함을 뜻
x, y 매개값은 픽셀 단위의 좌표값인데, 컨테이너의 좌 측 상단이 (0, 0)이고 우측이 x축, 하단이 y축이다. x의 최대값은 컨테이너의 폭width이고, y의 최대값은 컨테이 너의 높이height이다.
width 매개값은 컴포넌트의 폭을 말하고, height 매개값은 컴포넌트의 높이를 말한다
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.setText("확인");
// 버튼이 위치할 좌표값과 폭과 높이 설정
// 버튼 생성(왼쪽상단) 할 위치 : 100, 50 여기에 생성, 70, 60 버튼의 크기
btnOk.setBounds(100, 50, 70, 60);
}
return btnOk;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
NullLayoutExample jFrame = new NullLayoutExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
버튼 생성(왼쪽상단) 할 위치 : 100, 50 여기에 생성, 70, 60 버튼의 크기
Pack
JWindow, JFrame, JDialog와 같이 java.awt.Window를 상속받는 최상위 레벨 컨테이너는 pack()이라는 메소드를 사용해서 내부의 컴포넌트의 크기에 맞게 컨테이너의 크기를 자동으로 조절할 수 있다
컴포넌트에는 PreferredSize라는 속성이 있는데, 이것은 컴포넌트의 기본 배치 크기를 말한다
- 컨테이너의 pack() 메소드가 호출되면 내부 컴포넌트의 getPreferredSize()를 호출해서 컴포넌트의 기본 배치 크기를 알아낸 뒤, 컨테이너의 크기를 계산한다.
- pack() 메소드는 내부 컴포넌트의 크기에 따라 컨테이너의 크기가 결정
- 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("FlowLayoutExample");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// FlowLayout으로 변경하고 버튼 추가
this.setLayout(new FlowLayout());
this.getContentPane().add(getBtnOk());
this.getContentPane().add(getBtnCancel());
this.pack(); // 컴포넌트의 배치에 따른 크기를 계산해서 컨테이너 크기를 지정
}
private JButton getBtnOk() {
if(btnOk == null) {
btnOk = new JButton();
btnOk.setText("확인");
}
return btnOk;
}
// Cancel 버튼생성
private JButton getBtnCancel() {
if(btnCancel == null) {
btnCancel = new JButton();
btnCancel.setText("취소");
}
return btnCancel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
PackExample jFrame = new PackExample();
jFrame.setVisible(true);
}
});
}
}
- 실행 결과 -
'자바' 카테고리의 다른 글
자바 UI - Swing (RadioButton 응용) (0) | 2023.02.16 |
---|---|
자바 UI - 03) Swing (이벤트처리기, 버튼 컴포넌트) (0) | 2023.02.16 |
자바 - Swing 컨테이너 구조 (Glasspane, JMenuBar와 ContentPane, LayeredPane) (2) | 2023.02.15 |
자바 UI - 01) Swing (Swing 소개 ,이벤트 디스패칭 스레드 ,Swing 컨테이너) (0) | 2023.02.15 |
자바 - 데이터베이스 입출력 (0) | 2023.02.13 |