배치 관리자 (Layout Manager)

yuzu sim's avatar
Jan 24, 2024
배치 관리자 (Layout Manager)

1. Layout Manager란?

컴포넌트들을 자동으로 배치하는 역할을 담당하는 클래스. (컨테이너마다 하나씩만 존재함) 컴포넌트들의 위치와 크기를 조정·관리하는 객체
 

2. Layout Manager의 종류 및 사용 예시

2-1. BorderLayout

컴포넌트들을 동, 서, 남, 북, 중앙 5개의 영역으로 나누어 배치. 주로 JFrame, JDialog와 같은 최상위 컨테이너의 디폴트 배치 관리자
notion image
BorderLayout 지정법 및 생성자
* add(button, "South"); = 배치할 때, "North", "South", "East", "West", "Center" 의 문자열을 사용 = 기본 값 : "Center" = 여러개의 컴포넌트를 같은 영역에 추가하면 : 마지막에 추가된 컴포넌트만 표시 = 중앙에 컴포넌트 추가하면 : 다른 컴포넌트가 없으면 컨테이너 전체 영역을 차지
* BorderLayout() * BorderLayout(int hGap, int vGap)
BorderLayout 예시 및 코드
notion image
 
코드
package ex08; import javax.swing.*; import java.awt.*; public class MyFrame02 extends JFrame { public MyFrame02() { setTitle("BorderLayoutTest"); setSize(300, 150); setLayout(new BorderLayout()); JButton b1 = new JButton("North"); JButton b2 = new JButton("South"); JButton b3 = new JButton("East"); JButton b4 = new JButton("West"); JButton b5 = new JButton("Center"); add(b1, "North"); add(b2, "South"); add(b3, "East"); add(b4, "West"); add(b5, "Center"); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } public static void main(String[] args) { MyFrame02 f01 = new MyFrame02(); } }
 

 
add(new JButton("North")); add(new JButton("South")); add(new JButton("East")); add(new JButton("West")); add(new JButton("Center")); 가 안되는 이유 >
notion image
💡
BorderLayout는 위치 지정을 정확하게 안해주면 무조건 중앙에 모두 배치되기 때문에 해당 코드 불가능
 

2-2. FlowLayout

컴포넌트들을 왼쪽에서 오른쪽으로, (추가되는 순서대로) 배치. (패널의 기본 배치 관리자) 공간이 부족하면 다음 줄로 넘어감
notion image
FlowLayout 생성자
* FlowLayout() * FlowLayout(int align) = align: 컴포넌트의 정렬 방식을 설정 = FlowLayout.LEFT, FlowLayout.CENTER, FlowLayout.RIGHT (왼쪽 정렬) (가운데 정렬) (오른쪽 정렬) * FlowLayout(int align, int hGap, int vGap) = hGap: 컴포넌트 사이의 가로 간격을 설정 = vGap: 컴포넌트 사이의 세로 간격을 설정 ex) setLayout(new FlowLayout(FlowLayout.CENTER, 10, 20));
 
notion image
💡
LEFT라고 하니, 왼쪽으로 정렬되어서 나오는 것 확인! * 지정 안하면 기본값은 CENTER인듯?
 
notion image
왼쪽 정렬, 컴포넌트와 컴포넌트의 가로·세로 공간이 50씩 띄워진 것 확인!
 
FlowLayout 예시 및 코드
notion image
notion image
이렇게 창을 늘리면 배치한 컴포넌트도 같이 늘어남
JButton b1 = new JButton("Button1")); add(b1); == add(new JButton("Button1"));
notion image
 
코드
package ex08; import javax.swing.*; import java.awt.*; public class MyFrame01 extends JFrame { public MyFrame01() { setTitle("FlowLayoutTest"); setSize(300, 150); setLayout(new FlowLayout(FlowLayout.LEFT, 50, 50)); add(new JButton("Button1")); add(new JButton("Button2")); add(new JButton("Button3")); add(new JButton("Button4")); add(new JButton("Button5")); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } public static void main(String[] args) { MyFrame01 f01 = new MyFrame01(); } }
 

2-3. GridLayout

컨테이너의 공간을 동일한 크기의 격자로 나누고, 이 격자에 컴포넌트들을 배치. (행과 열의 개수를 지정하여 컴포넌트를 배치)
notion image
GridLayout 생성자
* GridLayout() = 1행과 1열의 격자. 한 줄에 모두 배치 * GridLayout(int rows, int cols) = 행과 열의 수를 직접 지정하여 생성. 지정된 행과 열의 수에 맞추어 컴포넌트 배치 * GridLayout(int rows, int cols, int hGap, int vGap) = 행과 열의 수뿐만 아니라 가로 간격(hGap)과 세로 간격(vGap)도 지정하여 생성
 
GridLayout 예시 및 코드
notion image
notion image
 
코드
package ex08; import javax.swing.*; import java.awt.*; public class MyFrame03 extends JFrame { public MyFrame03() { setTitle("GridLayoutTest"); setSize(300, 150); setLayout(new GridLayout(2, 3)); add(new JButton("Button1")); add(new JButton("Button2")); add(new JButton("Button3")); add(new JButton("B4")); add(new JButton("Long Button5")); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } public static void main(String[] args) { MyFrame03 f01 = new MyFrame03(); } }
 
 

2-4. CardLayout

여러 개의 컴포넌트들을 (카드처럼) 겹쳐서 보여줄 때 사용. 한 번에 하나의 컴포넌트만 보이도록 관리함
notion image
CardLayout 메소드 (애는 메소드)
* next(container) = 주어진 컨테이너의 다음 카드로 이동 * previous(container) = 주어진 컨테이너의 이전 카드로 이동 * first(container) = 주어진 컨테이너의 첫번째 카드로 이동 * last(container) = 주어진 컨테이너의 마지막 카드로 이동 * 어떤 이벤트 발생 시, 위의 메소드를 호출하여서 카드를 변경함
💡
CardLayout 객체를 생성할 때가 아니라, 생성된 CardLayout 객체를 사용하여 컴포넌트 간의 전환을 수행할 때 호출되기 때문에 메소드!
 
CardLayout 예시 및 코드
notion image
notion image
버튼을 눌리자 번호가 바뀌는 것 확인! (= 다음 컴포넌트가 뜨는 것 확인!)
 
코드
package ex08; import javax.swing.*; import java.awt.*; public class MyFrame05 extends JFrame { JButton b1, b2, b3; Container cPane; CardLayout layoutm; public MyFrame05() { setTitle("BoarderLayoutTest"); setSize(300, 150); cPane = getContentPane(); layoutm = new CardLayout(); setLayout(layoutm); JButton b1 = new JButton("Card #1"); JButton b2 = new JButton("Card #2"); JButton b3 = new JButton("Card #3"); add(b1); add(b2); add(b3); b1.addActionListener(e -> layoutm.next(cPane)); b2.addActionListener(e -> layoutm.next(cPane)); b3.addActionListener(e -> layoutm.next(cPane)); setVisible(true); setDefaultCloseOperation(EXIT_ON_CLOSE); } public static void main(String[] args) { MyFrame05 f01 = new MyFrame05(); } }
코드 뜯어보기 & 안되는 이유
[ setLayout(new CardLayout());은 왜 안되나? ]
notion image
💡
버튼 b1을 클릭할 때마다, 새로운 CardLayout 객체가 생성되고, 그 객체의 next() 메서드가 호출되어 레이아웃이 변경된다. 그러나 이렇게 작성하면 항상 첫 번째 카드로 돌아가는 현상이 발생. 기존에 생성된 CardLayout 객체를 사용하여 레이아웃을 변경해야 함. 이를 위해서는 CardLayout 객체를 멤버 변수로 선언하고 생성자에서 초기화한 후, 버튼 클릭 이벤트 핸들러에서는 생성된 CardLayout 객체의 next() 메서드를 호출하여 레이아웃을 변경하도록 해야함!
💡
원하는 동작은 계속 새로운 객체를 생성하는 것이 아니라, 기존에 생성된 CardLayout 객체를 사용하여 레이아웃을 변경하는 것! > 버튼을 클릭할 때마다 ‘기존에 만들어둔’ b1, b2, b3들이 나와야 함.
 

 
[ cPane = getContentPane();는 왜 사용하는지? ]
💡
CardLayout 레이아웃을 적용하려면 어떤 공간에 컴포넌트를 배치할지를 지정해야 한다. 즉, cPane 변수는 CardLayout을 적용하고자 하는 컨테이너를 가리키는 변수
 

[ b1.addActionListener(e -> layoutm.next(cPane)); ]
cPane = 컨테이너 참조 변수. 현재, ContentPane으로 지정되어 있음. ContentPane 컨테이너에 있는 다음 카드 (b2, b3)로 이동한다.
💡
getContentPane() 메서드는 프레임의 컨텐츠 영역에 해당하는 컨테이너를 반환하여, 해당 컨테이너에 컴포넌트들을 추가하고 관리할 수 있게 해줌.
 

[ addActionListener() 메서드란? ]
버튼에 액션 리스너를 추가하는 메서드 액션 리스너는 사용자의 동작(예: 버튼 클릭)을 감지하고 그에 따른 동작을 수행하는 역할
 

 
[ b1.addActionListener(e -> layoutm.next(cPane)); 람다 표현식 ]
💡
액션 이벤트가 발생했을 때 실행될 동작을 정의하는 부분. layoutm이 참조하는 CardLayout 객체를 사용하여 cPane이 참조하는 컨테이너에서 다음 컴포넌트를 보여주는 역할(전환)을 한다.
b1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { layoutm.next(cPane); } }); [람다식] b1.addActionListener(e -> layoutm.next(cPane));
 
+) JPanel로는 불가능
 

2-5. ETC

BoxLayout : 컴포넌트들을 수평 또는 수직으로 일렬로 배치. 유연한 크기 조정이 가능
etc : GridBagLayout, GroupLayout 등 다양한 배치관리자가 존재.
 
 
 

3. Layout Manager 설정하기

1. 컴포넌트 크기에 대한 힌트
panel.setLayout(new BorderLayout()); - 패널에 배치 관리자 설정하는 방법
 
  1. 컴포넌트의 최소 크기 지정
button.setMinimumSize() / 컴포넌트명.setMinimumSize()
 
  1. 컴포넌트의 선호 크기 지정
button.setPreferredSize() ex) button.setMaximumSize(new Dimension(300, 200)); > 버튼의 최대 너비는 300픽셀, 최대 높이는 200픽셀로 제한
💡
Dimension 객체 : 너비와 높이를 나타내는 값
 
  1. 컴포넌트의 최대 크기 지정
button.setMaximumSize()
 

 
2. 컴포넌트 정렬에 대한 힌트 (Alignment - 가지런함)
setAlignmentX() - 가로 정렬 (0.0에서 1.0 사이의 값으로 지정) setAlignmentY() - 세로 정렬 (0.0에서 1.0 사이의 값으로 지정) ex) button.setAlignmentX(JComponent.CENTER_ALIGNMENT) //중앙 정렬 힌트 * CENTER_ALIGNMENT은 JComponent 클래스에 정의된 상수 * CENTER_ALIGNMENT 상수는 가로 정렬을 중앙으로 설정하는 값
setAlignmentX(float alignmentX) 의 매개변수가
  • 0.0 : 컴포넌트를 왼쪽으로 정렬
  • 0.5 : 컴포넌트를 가운데로 정렬
  • 1.0 : 컴포넌트를 오른쪽으로 정렬
 
 
 
💡
힌트 : 컴포넌트가 어느 정도의 크기를 가져야 하는지를 나타내는 값 (배치관리자에게 컴포넌트의 크기와 위치를 지정하기 위해 사용되는 값)
 
 
Share article

Coding_study