자바 스윙을 익혀보면 몇가지 난해한 기술이 있는데 그 중 하나를 꼽자면 단연 GridBagLayout 을 들 수 있다. 다른 레이아웃보다 사용자가 개입해서 다양한 레이아웃을 연출할 수 있으나 GridBagConstraints 를 설정하는 값들이 어떠한 경우에 쓰이는지 언뜻 봐서는 이해하기가 힘들고, 무엇보다도 서로 다른 맥락에서 쓰이는 설정값들  모두 int 형으로 정의되어서 혼란을 더욱 부추긴다.

GridBagLayout 은 사실상 GridBagConstraints 를 통해서 레이아웃을 설정하므로 GridBagConstraints 에서 설정할 값들의 맥락을 이해하는 과정이 선행되어야 한다.


1. 어디에 배치할 것인가?

gridx, gridy, gridWidth, gridHeigt

이것은 자식 컴포넌트들의 "좌표값"을 지정한다. (0,0)에서는 JLabel을, 그리고 그 옆인 (1, 0)에는 JTextField 를... 이런 식으로 자식 컴포넌트들의 위치를 지정해준다. 가장 기본적인 개념이므로 이해가 쉽다.

gridx, gridy 와 함께 사용되는 것이 gridWidth, gridHeight 이다. gridx와 gridy로 각각의 자식 컴포넌트가 공평하게 한 칸씩 차지한 상태에서 특정 컴포넌트에게 두개 또는 그 이상의 셀(Cell)을 수평, 수직으로 할당할 때 사용된다.

쉽게 말해서 html 에서 테이블을 다룰 때 rowspan 과 colspan을 떠올리면 된다.

colspan => gridWidth
rowspan => gridHeight

주의할 점은 이 네 개의 값이 자식 컴포넌트의 기본적인 위치만을 지정할 뿐이라는 것이다 . 즉, 지금 이 상태에서는 각 자식 컴포넌트의 높이나 너비와 같은 값들이 설정된 상태가 아니다.

2. 남는 공간을 얼마나 할당해줄 것인가?

weightX, weightY

"위치"를 할당하는 것과 "공간"을 할당하는 것은 서로 별개의 맥락이다. grid-family(gridx, gridy, gridwidth, gridHeight)는 컴포넌트의 위치만 지정해줄 뿐이고, 부모 컨테이너 안에서 각 컴포넌트가 얼만큼의 공간을 확보할 것인지는 weight-family(weightX, weightY)로 설정한다.

weight-family 값은 서로간의 상대적 비율을 의미하는데 수평으로 JLabel, JTextField, JButton 이렇게 세 개의 컴포넌트가 나란히 놓여있을 경우 다음과 같이 각 컴포넌트의 weight 값을 지정해줄 경우

JLable => 0.1
JTextField =>  0.3
JButton => 0.2
====> total weight : 0.6 ( 분모값으로 사용됨)

JLabel은 남는 공간의 1/6, text field는 1/2(50%), 그리고 button은 1/3(33.33%)을 차지하게 된다. 여기서 "남는 공간"이라고 한 점에 주목할 필요가 있는데, 부모 컨테이너의 너비가 400px 이고 세 개의 자식 컴포넌트의 기본적인 크기(getPrefferedSize())를 합한 너비가 250px 이라면 남는 공간인 150px(400-250) 에 대해서 위의 비율이 적용된다.

하지만 자식 컴포넌트의 너비가 부모 컨테이너의 너비보다 크다면? weight값을 적용할 여분의 공간이 없기 때문에 의미가 없어진다.

자식 컴포넌트의 너비가 각기 다르면 weight-family의 값을 똑같이 지정해도 전체 너비는 달라보이게 된다.(기본적인 자식 컴포넌트의 크기에 의해서)

아래 그림은 모두 똑같이 weightx를 0.1 씩 주었지만 기본적인 컴포넌트의 크기가 다르기 때문에 전체적인 너비가 다르게 나온다.

[그림1]여분의 공간은 똑같이 나눠갖는다.

따라서 weightx, weighty 가 "컴포넌트의 너비를 똑같이 유지해주지는 않는다"는 것을 알 수 있다. 양쪽 컴포넌트가 똑같은 너비를 갖도록 만들려고 weightx 값을 아무리 적용해도 원하는대로 화면이 안나오는 이유가 바로 여기에 있다.

위에서처럼 모든 컴포넌트에 weight값을 0보다 크게 지정해주면 남는 공간을 비율에 따라서 사이좋게 나눠갖는다. 하지만 label과 button에 0.0을 주고 textfield에 0.2을 준다면 남는 공간은 textfield 혼자 다 가지게 된다.

JLable => 0.0
JTextField =>  0.2
JButton => 0.0
total weight : 0.2

[그림2]textfield 혼자 여백을 다 갖는다.


이렇게 해서 창의 너비를 바꿀 때 특정 컴포넌트만 변하게 만들 수 있다. 남는 공간이 있어도 weight 가 0.0으로 지정되면 공간을 전혀 할당받지 못하고 창이 resizing 되더라도 여전히 동일한 너비로 남아있게 된다.

3. 남는 공간을 어떻게 채울 것인가?

fill

[그림2]를 보면 텍스트 필드의 크기가 "쪼그라"들어있는 것을 볼 수 있다. 관련 코드는 아래와 같은데 여기서 원하는 것은 text field가 저 여백을 꽉 채우도록 하는 것이다.
"fill" 을 통해서 남는 공간을 다 채울 것인지, 아니면 그냥 채우지 않고 놔둘 것인지를 설정할 수 있다. 아래와 같이 text field를 추가하기 전에 fill값을 지정해주면 weight를 통해서 확보한 여백을 컴포넌트가 몽땅 채우게 된다.

[그림3]여백을 꽉 채웠다.


fill 은 네 개의 값을 가질 수 있다.

GridBagConstraints.HORIZONTAL
남는 공간을 확보했을 경우 양 옆으로 꽉 채운다.

GridBagConstraints.VERTICAL
남는 공간을 확보했을 경우 위아래로 꽉 채운다.

GridBagConstraints.BOTH
남는 공간을 확보했을 경우 상하좌우 모두 꽉 채운다.

GridBagConstraints.NONE(기본값)
남는 공간이 있어도 채우지 말고 기본 크기를 유지한다.(기본값)

fill 역시 weight-family와 마찬가지로 "남는 공간"이 있어야 의미를 갖는다는 것을 알 수 있다.

[Swing] GridBagLayout에 대한 정리 2

'Dev > Java' 카테고리의 다른 글

[Swing] GridBagLayout에 대한 정리 2  (3) 2010.05.06
TDD 로 iBATIS 3 예제 구현  (0) 2010.05.05
[Java NIO] NIO Buffer method flip() rewind() mark() reset()  (2) 2010.05.02
Posted by yeori
,