Todo List 레이아웃을 잡아간 과정

샨티(shanti)·2022년 7월 6일
0

Study

목록 보기
1/11
post-thumbnail

메가테라 이월(ㅠㅠㅋ) 3주차의 과제는 바로 Todo List 만들기!
할 일을 텍스트로 입력한 뒤, 확인 버튼을 누르면 하단에 할 일 목록들이 누적되는 형태의 간단한 프로그램이다. (하지만 나에겐 절~대로 간단하지 않지)


실행된 화면만 보아도 아주아주 명확한 프로그램이다.
요구사항을 굳이 글로 쓰지 않아도 어떤 컴포넌트를 생성해서 추가해줘야 할 지 대강 감이 잡히리라 생각된다.

사실 지금 내 수준은 관심사의 분리를 위한 메소드화나 클래스 분리조차 제대로 수행하지 못하고 코드를 써 놓고도 '아니 이게 왜 돼?' 또는 '이건 왜안돼?' 하는 정도라...;; 이걸 어떻게 구현하나 고민이 한가득이었는데.

어찌되었건 아주 예쁜 모양새는 아니지만 꾸역 꾸역 최소 기능이라도 구현되는 코드를 만들어냈고, 트레이너님이 친히 리뷰도 해 주셨다.
사실 리뷰를 바탕으로 업그레이드를 한다기 보다는 아마 코드를 모조리, 싸그리 다 뜯어고쳐야 할 정도겠지만 그래도 기한 내에 과제를 했다는 점에서 마음의 부담이 좀 줄어든 건 사실이다.

갠적으론 이 과제를 수행하면서 꽤 골머리를 썩었던 것이 바로 '레이아웃'이었다.
레이아웃을 어떻게 잡아야 하는지도 모르겠거니와, 레이아웃은 잘 잡아놓고 언제 화면을 갱신해줘야 하는지 그 타이밍과 위치를 잘 이해하지 못해서 맞는 코드를 짜놓고서도 삭제했다가 살렸다가를 반복.

코드 입장에선 '차라리 날 죽여~~' 하고 싶었을지 모르겠다.

어쨌든, 이 레이아웃과의 전쟁은 비단 이번주 토요일부터 시작된 것이 아니다.
시간을 거슬러 올라가 이월되기 전, 즉 8주차 레벨테스트 과제에서도 애먹인 놈이 바로 이 레이아웃이었다.

JAVA의 Swing으로 프로그램을 구현한 분들은 모두 알겠지만 JFrame이나 JPanel 등 소위 컨테이너라고 불리우는 것들은 사용자가 레이아웃을 지정해 줄 수 있는데 이게 꼬여버리는 순간부터 세상 모든 인류애는 사라지고 손발을 덜덜 떨며 분노에 찬 한 인간만이 컴퓨터 앞에 앉아있게 된다.

아래 사진은 뭔 짓거리를 해도(사실은 내가 잘못된 짓거리를 한 것이겠지만) 원하는 모양을 뱉어내주지 않는 내 프로그램에게 넘나 서운해서
패널과 프레임에 백그라운드 컬러를 입혀본 결과물이다.


ㅋ. 보기만 해도 빡침 ㅋ
색칠공부 함? ㅋㅋ... 후.

저 꼴을 가지고 일주일 내도록 씨름해도 풀리지 않아 결국 마음에 들지 않는 결과물을 제출했기에, Todo list만큼은 레이아웃 문제 없이 만들어보고 싶은 욕심이 있었다.
그럼에도 불구하고 역시나 조져지는 건 나였지.

하지만 지난주보다 달라진 점도 분명히 있었다.
바로 '여러가지 실험을 통해 더 나은 방법을 찾아간 것'!!

레벨테스트 기간에는 실험이고 나발이고 그냥 JFrame 안에 셀 수도 없는 JPanel들만 때려넣고 앉아있었다면
이번주에는 아침 일찍 일어나 반복학습 과제를 모두 해치워놓고 레이아웃과의 전쟁을 위해 여러가지 실험을 해 본 것이 결론적으론 큰 도움이 되었다.
뿐만 아니라 나 혼자 고민했다면 해결되지 않았을 문제가 되었겠지만, 동료들과 같이 이야기를 나누며 빠르게 방향성을 찾았던 것 같다.

아래 사진 2장은 적어도 '내가 의도한 레이아웃 방향'을 구현한 Todo List 어플리케이션의 모습이다.



이 역시 프레임과 패널에 각각 컬러를 입혔기 때문에 눈뽕(?) 느낌이 나는데,
혹여라도 프레임과 패널 때문에 고생하고 있는 분들이 계시다면 각 컨테이너에 컬러를 입혀서 확인하는 것을 추천한다.

// 배경색을 입히고 싶은 프레임, 또는 패널에 배경색 입히기
// .setBackground(Color.원하는 색상);

public void initContentPanel() {
    contentPanel = new JPanel();
    contentPanel.setBackground(Color.yellow);
    frame.add(contentPanel);
  }

실제로 위 사진들에서 컨텐트 패널이 위치한 곳은 노란색임을 알 수 있다.

할튼. 근 2주에 걸친 고민 때문에 이번 기회에 JFrame과 JPanel의 레이아웃에 대해 좀 더 깊이있게 알게 되었는데,
아마 swing은 과제가 아닌 이상 앞으로는 마주칠 일이 많이 없을 것 같아 여기에 정리해두고 필요할 때마다 꺼내 보려고 한다.

특히 이번 블로그 글은 각 개념들에 대한 이론 정리라기 보다는

  1. 내가 문제를 해결해 나간 프로세스
  2. 실제로 적용할 수 있었던 필요한 정보

이 두가지에 대해서만 다룰 예정이므로 레이아웃에 대한 '공부'가 필요한 분들은 공식 문서를 참고할 것을 강력히 권한다.

구현 방법

다행(?)스럽게도 오랜시간 실패가 축적되었기 때문에 실패한 방법들을 교묘하게 피해가서 결국은 되는 모양새를 만들어냈다.
동료와 이야기하면서 잡은 레이아웃 방향을 아래와 같이 설정했고, 생각했던 방향과 맞아들어감과 동시에 잘 출력이 되었다.

  1. 프레임(JFrame) 셋팅
  • JFrame의 Layout 기본값은 BorderLayout
  1. 상단 컴포넌트들('할 일 목록' title, '할 일 :' subtitle, 텍스트 입력칸, 추가 버튼)을 모두 아우를 수 있는 컨테이너인 패널(JPanel) 셋팅
  • frame에 추가 시 frame의 BorderLayout 위치 중 'PAGE_START'에 위치시켜 주기
  • Title(할 일 목록)은 JLabel을 생성하여 구현해 준 뒤 해당 컨테이너 패널의 BorderLayout 위치 중 'PAGE_START'에 위치시켜 주기
  • 단, JPanel의 Layout 기본값은 FlowLayout임. 따라서 패널의 레이아웃을 BorderLayout으로 설정해주는 작업을 먼저 실행해야 함
  • form 요소(할 일 목록 이라는 subtitle, 텍스트 입력을 받는 JTextField, 추가 버튼 JButton를 한데 묶어 줄 또다른 컨테이너(JPanel)을 먼저 생성해 준 뒤 그 패널에 각각의 컴포넌트들을 add.
  1. 하단 콘텐트 패널(JPanel) 셋팅
  • 콘텐트 패널에는 레이아웃을 별도로 지정하지 않도록 함. 그리고 frame에 그냥 추가하도록 함(frame 상단 영역은 '상단 컴포넌트'가 차지하고 있으며, 콘텐트 패널은 그냥 add된 상태이므로 상단 영역을 침범하지 않는 구역 내에서 전체를 커버함
  1. 할 일 목록이 추가되는 순간 실현되며 콘텐트 패널 위에 얹어질 tasks 패널(JPanel)
  • 추가되는 컴포넌트들(체크박스, 라벨, 삭제버튼)이 아래로 떨어지면서 정렬되어야 하므로 GridLayout 잡아구지

GridLayout에 대한 오해!

이번 실험을 통해 'GridLayout'에 대한 오해를 풀었다는 점이 정말 큰 소득이라고 생각한다.
대상 컨테이너.setLayout(new GridLayout(row, column)
위와 같은 형태로 적용할 수 있는 GridLayout은 아마도 FlowLayout과 함께 꽤 많이 사용되고 있는 레이아웃 중 하나일 것이다.

비단 Swing 뿐만 아니라 html, css에서도 사용되는 것으로 알고있다.

그런데, 내가 이 GridLayout에 대해 단단히 오해하고 있었던 것이 하나 있다. 바로 '전체 영역'을 대상으로 레이아웃이 분할될 것이라는 오해였다.

무슨 이야기냐, 예시를 가지고 이야기해보자.

예를 들어 콘텐트 패널에 그리드 레이아웃을 아래와 같이 적용했다고 치자.
contentPanel.setLayout(new GridLayout(2, 1))

그리고 나서 할일을 입력한 뒤 추가를 하면 기가 맥히게~~ 위와 같은 모습으로 할일 목록이 나타났다.
저 두 간극을 좁힐 방법은 없다.(적어도 GridLayout을 적용한다면)

그렇기 때문에 이제까지 내가 레이아웃을 잘못 적용했다는 생각은 하지 않은 채,
아~ GridLayout은 패널이나 프레임 전 영역에 적용되는 것이구나~ 라고 오해했던 터였다.

하지만 아래 사진을 통해 알 수 있듯, GridLayout은 패널이나 프레임 전 영역을 column 수로 나누거나 row 수로 나누는 것은 아니다.
그저 내가 위 사진처럼 콘텐트 패널이 뎅겅 두동강 나게 GridLayout을 잘못 적용한 탓인거다.
컴퓨터는 거짓말을 하지 않는다고 그랬다.. 휴.


추가한 할 일 목록들이 정교하게 아래로 정렬되고 있는데 놀랍게도 GridLayout을 적용한 것이다.
노란색 콘텐트패널을 뎅겅 자르고, 또 뎅겅 잘라서 들어가는 것이 아니라 차곡 차곡 아래로 쌓이고 있는 모습을 볼 수 있다.

참. 이번에 새롭게 안 사실. row와 column 값에 0도 들어갈 수 있다는 사실!
추후에 컴포넌트가 추가되면 알아서, 자동으로 GridLayout을 맞춰준다.

0이 들어가면 안된다고 생각했을 땐, 내가 최종적으로 추가하고 싶은 컴포넌트의 갯수를 파악해야 한다는 부담이 있었는데 그 부담이 확- 줄어들었다.
앞으로 코드를 짤 때 좀 더 편한 마음으로 할 수 있을 것 같다.


JFrame, JPanel 둘이 같은 레이아웃 아니었어?

지난 TIL에도 쓴 내용이긴 한데, 가장 근본적인 원인은 여기에 있었다.
두 컨테이너가 레이아웃 디폴트가 모두 'BorderLayout'이라고 생각하고 있었기 때문에 아무리, 무슨 짓을 해도 원하는 결과가 나오지 않았던 것이다.

위에서도 정리했지만 결론은 JFrame의 기본 레이아웃: BorderLayout, JPanel의 기본 레이아웃: FlowLayout이다.
그러니 백날 패널에 컴포넌트 add 하면서 소심하게 붙인 BorderLayout 페이지 스타트가 씨알도 안먹혔던 것이다.

panel.add(label, BorderLayout(PAGE_START));

뭐... 어쩌라고... 하는 기분이었겠지 콤퓨타는?
어휴. 여튼 이 사실을 깨닫고는 레이아웃을 싹- 다시 잡아주니 원하는 모양대로 출력이 되었다.

이번 레이아웃 사태(?)를 겪으며 깨달은 바 3가지가 있다.

  1. 다짜고짜 레이아웃 여기저기 설정하지 말고, 계획을 해라 계획
    갠적으론 이거 정말 중요하다고 생각한다. 옆에 있는 찢어진 종이 주워다가 레이아웃을 구상하면서 결국은 만들어냈다.
    머릿속으로 상상하지 말고 손으로 그리고, 고민하고, 계획을 한 뒤에 레이아웃을 주자. 안그러면 되돌리는 시간이 너무 오래걸린다.


실제로 손으로 쓴 뒤에 구현했더니 됐다. 하하.

  1. 헷갈릴 땐 패널마다 색칠해서 눈으로, 정확히 확인한다.
    내가 생각하는 영역과 실제로 컨테이너, 컴포넌트가 차지하고 있는 영역이 다를 수 있다. 눈으로 확인하기 전까지는 쉽사리 믿지 말자~

  2. 사실 중요한 건 따로있다.

    Swing 자체보다도 UI / 비즈니스 로직이 있는 레이어의 구분하는 시도가 제일 핵심입니다.
    from. 메가테라 홀맨

Todo list 만들기... 끝나지 않았다.
내일과 내일 모레, 또 얼만큼 만들어볼 수 있을지 모르겠지만 그 다음 구현 때에는 홀맨님의 조언을 발판 삼아 UI요소와 비즈니스 로직을 구분하는 연습을 꼭 해내고 말리라.

레이아웃, 고마웠고 다신 만나지 말자~ (응?)

profile
가벼운 사진, 그렇지 못한 글

0개의 댓글