1996년 3월 19일 첫 출판, 1998년 6월 12일 최종 갱신


앞 페이지 뒷 페이지 색인


추상 윈도우 툴킷 패키지

자바에 있어서 java.applet 패키지와 아울러 가장 중요한 패키지 중의 하나는 java.awt 패키지이다. 자바의 윈도우 시스템인 추상 윈도우 툴킷(Abstract Window Toolkit)에 관련된 클래스들로 구성되어 있으며 java.applet.Applet 클래스가 java.awt.Panel에서 파생되었기 때문에 애플릿의 이해를 위해서도 자세히 알아둘 필요가 있는 패키지이다. 자바의 그래픽 사용자 인터페이스는 모두 AWT 패키지에 기반을 두고 있다.
먼저 java.awt 패키지의 주요 클래스 계층 구조부터 알아 두자.(아래 표는 JDK 1.1.x 버전에 따른 것이다.)

 
  • class java.awt.Component (implements java.awt.image.ImageObserver, java.awt.MenuContainer, java.io.Serializable)
    • class java.awt.Button
    • class java.awt.Canvas
    • class java.awt.Checkbox (implements java.awt.ItemSelectable)
    • class java.awt.Choice (implements java.awt.ItemSelectable)
    • class java.awt.Container
      • class java.awt.Panel
        • class java.applet.Applet
      • class java.awt.ScrollPane
      • class java.awt.Window
        • class java.awt.Dialog
          • class java.awt.FileDialog
        • class java.awt.Frame (implements java.awt.MenuContainer)
    • class java.awt.Label
    • class java.awt.List (implements java.awt.ItemSelectable)
    • class java.awt.Scrollbar (implements java.awt.Adjustable)
    • class java.awt.TextComponent
      • class java.awt.TextArea
      • class java.awt.TextField



그림에서 보는 바와 같이 각 윈도우 컴퍼넌트 클래스들은 모두 Component 클래스에서 파생되고 있다.
Button, Canvas, Checkbox, Choice, Label, List, Scrollbar 클래스들은 바로 Component 클래스에서 파생되고 Window 클래스와 Panel 클래스가 Component 클래스에서 파생된 Container 클래스에서 파생된다. Panel 클래스는 앞에서 설명하였듯이 java.applet.Applet 클래스를 자식 클래스로 두고 있고 Window 클래스는 그 아래에 Dialog와 Frame 클래스를 파생한다.
TextArea와 TextField 클래스는 TextComponent 클래스를 거쳐 Component 클래스에서 파생되었다.
마이크로소프트 윈도우 시스템이나 유닉스의 X 윈도우 시스템 프로그래밍에서와 유사하게 이 클래스들은 윈도우 시스템의 프로그래밍은 이벤트 구동(event-driven, 마이크로소프트 윈도우 시스템에서는 메시지 구동message-driven이라고도 한다.)으로 동작하므로 이벤트 처리 방식의 프로그래밍에 익숙해야 이해가 쉬울 것이다.
이외에도 java.awt 패키지에는 그래픽, 폰트, 컬러, 레이아웃 관련 클래스들이 존재한다.
주요 클래스를 살펴보자.

AWT 패키지의 주요 클래스들

1) Component 클래스 : Object 클래스에서 직접 파생되는 클래스로 모든 추상 윈도우 툴킷(AWT) 윈도우 컴퍼넌트 클래스들의 포괄적인 부모 클래스이다. 마우스나 키 입력 등 이벤트에 반응하고 폰트, 그래픽 등에 관련된 도구 등 윈도우에 관련된 일반적인 메소드들을 가지고 있다.
2) Container 클래스 : Component 클래스에서 파생되는 클래스로 역시 일반적인 윈도우를 표현하는 클래스이지만 내부에 다른 AWT 객체들(즉 버튼, 체크박스 등의 객체들)을 둘 수 있는 클래스이다. 내부에 AWT 객체들을 배치하는 방식을 지정하는 메소드 등이 있어 Container 내부에 배치되는 여러 가지 AWT 객체들을 보다 쉽게 배치할 수 있도록 해준다.
3) Window 클래스 : Container 클래스에서 파생되며 경계선과 메뉴바가 없는 최상위 윈도우이다. 여기에서 상위의 의미는 윈도우들 간의 관계를 의미한다. 예를 들어 OK 버튼이 하나 있는 대화상자를 생각해보면 대화상자 윈도우가 버튼의 상위 윈도우이다. (기본 레이아웃 관리자 : BorderLayout, 레이아웃 관리자에 대해서는 뒤에서 자세히 다룬다.)
4) Frame 클래스 : Window 클래스에서 파생되며, 같은 최상위 윈도우이지만 경계선과 메뉴바를 가진다. 메뉴바가 가지는 전형적인 윈도우를 구성한다. (기본 레이아웃 관리자 : BorderLayout)
5) Panel 클래스 : Container 클래스에서 파생되며 다른 Container의 내부에 사용될 수 있다. Applet 클래스의 상위 클래스이다. 하위 패널을 사용하여 복잡한 레이아웃을 만들거나 사용자 정의 Container를 만들 수 있다. (기본 레이아웃 관리자 : FlowLayout)
6) Dialog 클래스 : 대화상자를 만드는 최상위 클래스이다. (기본 레이아웃 관리자 : BorderLayout)
7) FileDialog 클래스 : Dialog 클래스의 하위 클래스로 파일 선택 대화상자를 만든다.
8) Canvas 클래스 : 특별한 기능을 가진 하위 GUI 성분 클래스로 만들 수 있도록 한 다목적 AWT 요소이다. 이름 그대로 그래픽을 만드는 데 사용할 수도 있고 사용자 입력을 가로채어 다른 기능을 추가할 수도 있다.
9) Button, Checkbox, Label, List, Scrollbar, TextArea, TextField 클래스 : 각각 하나의 GUI 요소를 표현하는 윈도우 클래스들이다. 아래 그림을 참고하자.
[그림] Button에서 TextField까지의 AWT 요소들을 차례로 나타낸 간단한 
자바 프로그램
다음은 위 예제 프로그램의 소스이다. 버튼을 누르면 종료한다.

AWTExample.java

10) Event 클래스 : Event는 지역의 GUI 플랫폼에서 발생하는 이벤트들을 대신하는 플랫폼 독립적인 클래스이다. 하나의 윈도우 요소가 처리해야 할 이벤트가 발생하면 AWT가 해당 요소로 전달한다. Event 클래스는 이들 이벤트의 정보를 가지고 있는 클래스 이다. 해당하는 윈도우 요소가 이벤트를 처리하지 않으면 AWT는 해당 윈도우의 상위 윈도우에게 이벤트를 전달한다. 따라서 Container는 자기 내부의 윈도우 요소들이 처리하지 않은 모든 이벤트들을 처리할 수 있다.
11) Graphics 클래스 : Graphics는 그래픽에 관련된 다양한 도구들을 포괄하고 있는 클래스이다. 선, 원, 육면체, 그림, 글자 등의 다양한 그래픽 요소들을 화면에 나타내는 데 사용된다.

Component, Container 클래스의 주요 메소드들

AWT 윈도우 요소들의 부모 클래스인 Component와 Container 클래스의 주요 메소드들은 자식 윈도우 클래스들에 그대로 상속되어 사용되며 AWT 프로그래밍의 핵심이라 할 수 있다.

먼저 AWT의 최상위 클래스인 Component 클래스의 주요 메소드부터 살펴보자.
Component 클래스가 모든 AWT 윈도우 구성 요소 클래스들의 부모 클래스이므로 이 메소드들은 모든 윈도우 구성 요소에서 공통적으로 사용가능한 메소드들이다.(이벤트에 관련된 메소드들은 나중에 설명한다.)

  1. public Container getParent() : 상위 윈도우를 구할 때 사용한다.
  2. public Point getLocation() : 상위 윈도우의 좌표 공간에서 현재의 위치를 구한다.
  3. public Dimension getSize() : 현재 크기를 구한다. Dimension은 높이와 폭으로 구성되는 클래스이다.
  4. public synchronized void setEnabled(boolean b) : 인자 값에 따라 사용자 입력을 받을 수 있도록 혹은 없도록 한다. 기본 값은 입력을 받을 수 있는 것이다.
  5. public synchronized void setVisible(boolean b) : 인자 값에 따라 화면에 나타내거나 화면에서 감춘다.
  6. public synchronized void setForeground(Color c) : 주어진 색을 전경색으로 표시한다.
  7. public synchronized void setBackground(Color c) : 주어진 색을 배경색으로 표시한다.
  8. public void setLocation(int x, int y) : 새로운 위치로 이동시킨다. x, y 좌표는 상위 윈도우의 좌표 공간 값으로 주어진다.
  9. public void setSize(int width, int height) : 주어진 폭과 높이로 윈도우 크기를 변경한다.
  10. public synchronized void setBounds(int x, int y, int width, int height) : setLocation(x, y), setSize(width, height)를 연속으로 호출한 효과를 낸다.
  11. public Graphics getGraphics() : 해당 윈도우에 그림을 그리기 위한 그래픽 컨텍스트(마이크로소프트 윈도우 시스템에서는 그래픽 장치 컨텍스트graphic device context라고 한다)를 얻을 때 사용한다.
  12. public FontMetrics getFontMetrics(Font font) : 주어진 글꼴에 관련하여 글꼴 구조 정보를 구할 때 사용한다. 글꼴의 폭이나 높이 등을 구할 때 자주 사용한다.
  13. public void paint(Graphics g) : 윈도우를 다시 그릴 때 AWT에 의해 불려진다. 이 메소드가 불려지는 때에는 처음으로 윈도우 컴퍼넌트가 화면에 나타날 때, 혹은 다른 윈도우에 의하여 가려졌다가 다시 나타날 때, 또 사용자가 직접 repaint() 메소드를 호출하였을 때 등이다. 마이크로소프트 윈도우 프로그래머는 WM_PAINT 메시지를 생각하면 쉽게 이해할 수 있다.
  14. public void repaint() : AWT에게 컴퍼넌트를 완전히 다시 그리도록 요청한다. 이 명령은 실제로는 가능한 한 빨리 update()를 호출하도록 AWT에게 요청하는 것이 된다.
  15. public void update(Graphics g) : repaint() 요청에 따라 AWT에 의해 호출된다. 현재 컴퍼넌트를 지운 다음 paint()를 호출하는 것이 기본 동작이다.
  16. public void requestFocus() : 입력 포커스를 요청한다.
  17. public void transferFocus() : 다음 윈도우로 입력 포커스를 옮긴다.
  18. public void setCursor(Cursor cursor) : 컴퍼넌트의 마우스 커서를 변경한다.

Component의 도구들이 윈도우의 일반적인 행위에 대한 것이라면 Container 클래스의 도구들은 주로 하위 윈도우를 만들고 배치하는 것에 관련된 도구들이다.

하위 윈도우

윈도우 시스템에서 하나의 복합적인 윈도우를 구성할 때 여러 개의 윈도우를 겹쳐서 만든다는 원리에 따라 가장 바닥에 있는 큰 윈도우를 최상위 윈도우로 하고 그 위에 포개지는 각 윈도우를 하위 윈도우라고 한다. 예를 들어, 대화상자 윈도우에서 대화상자 전체 크기를 구성하는 윈도우는 최상위 윈도우가 되고 대화상자의 OK 버튼은 그 위에 존재하는 하위 윈도우가 된다. 윈도우의 구성요소를 표시할 때 최상위 윈도우를 정점에 두고 그 위에 놓이는 각 윈도우를 자식처럼 표현하여 윈도우 계층 구조를 표시하기 때문에 상하 개념이 조금 다른 것이다. 윈도우 계층 구조에서의 상하와 클래스 계층 구조에서의 상하를 혼돈하지 말 것.

하위 윈도우들을 배치할 때에는 뒤에서 설명할 레이아웃 관리자 즉, LayoutManager 클래스들이 중요하게 작용한다. Container 클래스가 Component 클래스의 자식 클래스이므로 Component 클래스의 메소드 또한 모두 사용할 수 있음을 명심하자.

  1. public void setLayout(LayoutManager mgr) : 윈도우의 레이아웃 관리자를 지정한다. 레이아웃 관리자 클래스에는 BorderLayout, CardLayout, FlowLayout, GridBagLayout, GridLayout 등이 있다. 레이아웃 관리자 클래스를 사용하면 쉽게 하위 윈도우의 위치를 지정할 수 있고 또 윈도우의 크기가 변경되었을 때 자동으로 재배치할 수 있다.
  2. public synchronized void doLayout() : 레이아웃 관리자에 의해 레이아웃을 한 후에 (하위 윈도우들을 생성한 후에) 호출하여 윈도우들을 유효화한다. 이 메소드를 코드에서 직접 호출하지 말고 대신에 validate()를 호출하여 결과적으로 doLayout()이 수행되도록 한다.
  3. public synchronized Component[] getComponents() : 이 윈도우 내부의 모든 하위 윈도우들을 얻는다.
  4. public Insets getInsets() : 이 윈도우의 인셋(inset)을 지정한다. 인셋은 내부의 하위 윈도우들과 네 방향(상하좌우)의 경계 부분의 크기를 말한다. 예를 들어 프레임 윈도우는 타이틀 바에 해당하는 위쪽 인셋을 가질 것이다.
  5. public Component add(Component comp) : 인자로 주어진 윈도우를 하위 윈도우로 하여 내부에 배치한다.
  6. public synchronized void remove(Component comp) : 지정된 하위 윈도우를 제거한다.
  7. public synchronized void removeAll() : 모든 하위 윈도우들을 제거한다.
  8. public LayoutManager getLayout() : 해당 윈도우의 레이아웃 관리자를 구한다.

레이아웃 관리자 클래스

Container 윈도우가 하위 윈도우를 배치할 때 사용하는 setLayout() 메소드는 LayoutManager 인터페이스를 인자로 가진다. 즉, LayoutManager 인터페이스를 구현한 객체를 인자로 갖는 것이다. 기본적으로 제공되는 레이아웃 관리자 객체는 다음 다섯 개다. (이들 클래스는 모두 LayoutManager 인터페이스를 구현한다.)

1. BorderLayout 클래스

이 레이아웃 관리자 클래스는 add() 도구를 사용하여 하위 윈도우를 다음 다섯 가지 방식으로 배치한다.
North(Container 윈도우의 북쪽), South(남쪽), East(동쪽), West(서쪽), Center(중앙)
배치가 되는 순서는 먼저 North, South, East, West에 해당하는 하위 윈도우들을 각각의 기본 크기(Component 클래스의 메소드인 getPreferredSize()의 반환값이다.) 값과 Container 윈도우의 크기 한계를 감안하여 배치하고 그 다음 여백으로 Center에 해당하는 윈도우를 배치한다.
Window나 Frame 클래스는 레이아웃 관리자를 별도로 지정하지 않을 경우 기본값으로 BorderLayout을 레이아웃 관리자로 지정한다.
실제 사용 방법은 다음 예제 소스를 참조한다.

BorderLayoutApplet.java

2. FlowLayout 클래스

하위 윈도우들을 왼쪽에서 오른쪽으로 한 줄로 정렬한다. Container 윈도우가 add() 도구를 사용하면 왼쪽에서부터 차례로 하위 윈도우를 추가시킨다. static int 상수로 LEFT, RIGHT, CENTER가 있어 정렬 방식을 지정할 수 있다.
Panel 클래스(Panel의 자식 클래스인 Applet 클래스를 포함하여)는 레이아웃 관리자를 별도로 지정하지 않을 경우 기본값으로 FlowLayout을 레이아웃 관리자로 지정한다.

FlowLayout의 생성자는 몇 가지가 있는데 인자가 없는 생성자는 기본값으로 FlowLayout.CENTER를 정렬 방식으로 간주한다.
실제 사용 방법은 다음 예제 소스를 참조한다.

FlowLayoutApplet.java

3. GridLayout 클래스

컴퍼넌트를 일정한 행과 열의 그리드(격자)로 구분하여 해당 그리드 안에 하위 윈도우를 하나씩 배치한다.

인자가 없는 생성자는 1행, 1열의 그리드로 간주한다.
실제 사용 방법은 다음 예제 소스를 참조한다.

GridLayoutApplet.java

4. GridBagLayout 클래스

이 레이아웃 관리자 클래스를 사용하면 하위 윈도우들의 크기를 다르게 하여 자유롭게 수직, 수평으로 유연하게 배치할 수 있다. 각각의 하위 윈도우는 사각형으로 구분된 그리드들 중 하나 혹은 여러 개를 자신의 디스플레이 영역으로 차지하여 배치된다.

각 하위 윈도우가 배치되는 세부적인 방식은 별도의 GridBagConstraints 클래스를 통해서 지정한다. 이 클래스는 anchor, fill, gridheight, gridwidth, gridx, gridy, insets, ipadx, ipady, weightx, weighty 등의 필드를 가지며 이 필드들의 값이 실제 배치되는 방식을 구체적으로 지정하게 된다. 따라서, 이 레이아웃을 제대로 사용하기 위해서는 GridBagConstraints 클래스의 필드를 정확하게 이해해야 한다.

gridx, gridy : 해당 하위 윈도우의 디스플레이 영역에서 왼쪽 윗 부분을 기준점으로하여 위치를 지정한다. 가장 왼쪽 위의 그리드에 자리하면 gridx와 gridy 모두 0이 된다. 기본값인 GridBagConstraints.RELATIVE를 gridx의 값으로 사용하면 더해지는 순서에 따라 단순히 오른쪽에 배치된다.(마찬가지로 gridy의 값으로 RELATIVE가 사용되면 순서에 따라 단순히 아래쪽에 배치된다.)

gridwidth, gridheight : 디스플레이 영역의 그리드 개수를 행 방향으로(gridwidth), 혹은 열 방향으로(gridheight) 지정한다. 기본값은 1이다. GridBagConstraints.REMAINDER 값은 행 혹은 열 가운데 마지막 하나를 뜻하고 GridBagConstraints.RELATIVE 값은 마지막 바로 왼쪽(혹은 바로 위)를 뜻한다.

fill : 하위 윈도우의 디스플레이 영역(지정된 그리드 영역)이 요구되는 하위 윈도우의 크기보다 클 때 컴퍼넌트 윈도우의 크기를 결정하는 데 사용된다. 기본값인 GridBagConstraint.NONE 값을 지정하면 윈도우의 크기를 기본 크기로 유지한다. GridBagConstraint.HORIZONTAL 값을 지정하면 디스플레이 영역의 폭과 윈도우의 폭이 같도록 윈도우의 폭을 넓힌다. GridBagConstraint.VERTICAL 값을 지정하면 디스플레이 영역의 높이와 하위 윈도우의 높이가 같도록 윈도우의 높이를 높인다. GridBagConstraint.BOTH 값을 지정하면 하위 윈도우가 자 신의 디스플레이 영역을 완전히 채우게 된다.

ipadx, ipady : 내부 여백의 값으로 하위 윈도우의 최소 크기에 추가되어 계산된다.

insets : 외부 여백의 값으로 디스플레이 영역의 가장자리와 하위 윈도우 간의 최소한의 거리를 지정한다.

anchor : 하위 윈도우의 크기가 디스플레이 영역보다 작을 때 영역 내의 어느 곳에 하위 윈도우를 배치할지 결정하는 데 사용된다. 기본값은 GridBagConstraints.CENTER로 가운데로 배치한다. 그 외 GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST, GridBagConstraints.EAST, GridBagConstraints.SOUTHEAST, GridBagConstraints.SOUTH, GridBagConstraints.SOUTHWEST, GridBagConstraints.WEST, GridBagConstraints.NORTHWEST 등의 값을 가질 수 있다. 물론 fill 값이 BOTH로 지정되어 있다면 의미가 없을 것이다.

weightx, weighty : 여백을 분배하는 데 사용되는 변수로 기본값은 0이다. 모두 0가 되면 가운데로 모이게 될 것이다. 값이 0이 아닌 컴퍼넌트들이 가로 혹은 세로 방향으로 값의 크기에 따라 여백을 분배하며 배치하게 된다.(아래의 예제 애플릿 참조)

다음은 GridBagLayout 클래스를 사용하여 열 개의 버튼 윈도우를 배치한 예이다. 모든 버튼은 fill 값으로 GridBagConstraints.BOTH를 가진다. fill 외에 여기에 사용된 기본값이 아닌 각 변수 값은 다음과 같다.

버튼4: gridwidth=GridBagConstraints.REMAINDER // 버튼4의 디스플레이 영역은 행에서 마지막에 위치
버튼5: gridwidth=GridBagConstraints.REMAINDER // 버튼5는 행에서 마지막에 위치
버튼6: gridwidth=GridBagConstraints.RELATIVE // 버튼6은 행에서 마지막 바로 앞의 것
버튼7: gridwidth=GridBagConstraints.REMAINDER // 버튼7은 행에서 마지막에 위치
버튼8: gridheight=2 // 버튼8은 세로 방향으로 그리드 두 개에 걸친다.
버튼9, 버튼10: gridwidth=GridBagConstraints.REMAINDER // 버튼9,10은 각각 행에서 마지막 위치

fill 값을 BOTH로 하였기 때문에 버튼의 크기가 바로 각각의 디스플레이 영역이다. weight 값이 모두 기본값인 0으로 되어 있어 처음에는 모든 버튼들이 가운데에 몰려 있다. 아래의 텍스트 필드에서 weight.x 값과 weight.y값을 특정 버튼에 지정할 수 있게 하였다. 먼저 오른쪽의 선택상자에서 지정할 버튼을 선택한 다음, 텍스트필드에 값을 입력하고 Apply 버튼을 누르면 지정된 값에 따라 다시 배치한다. 테스트해보라.

GridBagLayoutApplet.java

5. CardLayout 클래스

탭 대화상자(tabbed dialogs)나 동적인 대화상자를 가능하게 하는 레이아웃 관리자 클래스이다. 여러 장의 카드가 있으나 보이는 카드는 하나만 있다는 개념에서 나온 이름이다. add 메소드를 실행할 때 각 카드를 식별할 수 있는 문자열을 지정해야 하고, 나중에 show 메소드에 이 문자열을 인자로 줘서 해당 카드가 보이게 할 수 있다. first(), last(), next(), previous() 등의 도구를 사용하여 카드 간에 순차적으로 이동할 수도 있다. 사용 방법은 다음 예제를 참고한다. 예제에서는 간단히 하기 위해 카드로 버튼을 사용하고 있으나 실제로는 여러 컴퍼넌트를 포함하는 패널이나 그래픽 요소를 담은 캔버스와 같은 것이 주로 사용될 것이다.

CardLayoutApplet.java

 

6. 레이아웃 관리자 클래스를 지정하지 않을 경우

다음 예제에서 reshape(JDK 1.1에서는 setBounds로 이름이 변경된다.) 메소드를 사용하여 위치와 크기를 직접 지정하지 않고 단순히 add만 하면 실제로는 버튼이 보이지 않을 수도 있다.

이렇게 레이아웃 관리자 클래스가 지정되지 않을 경우(즉 null 값을 레이아웃 관리자로 지정한 경우), 컴퍼넌트의 위치와 크기를 정확하게 지정하는 것은 프로그래머의 책임이 되고, 컴퍼넌트를 포함하는 컨테이너 윈도우가 크기 변경 등으로 갱신될 때 하위 컴퍼넌트 윈도우들은 재배치되지 않는다. 다시 재배치하는 것 역시 프로그래머의 책임이 되는 것이다.

NullLayoutApplet.java

이벤트 처리

[추가 예정]

JFC 스윙 셋

[추가 예정]


앞 페이지 뒷 페이지 색인