올해는 머신러닝이다.
AWT 컴포넌트 소개 본문
1. AWT(ABSTRACT WINDOW TOOLKIT) 컴포넌트(COMPONENT)
4. 컨테이너와 레이아웃 관리자(LAYOUT MANAGER)
바. 그리드백 레이아웃 관리자(GridBagLayout)
사. 레이아웃 관리자를 사용하지 않는 레이아웃(Absolute Positioning)
마. 체크박스 메뉴 아이템(CheckboxMenuItem) 컴포넌트
제8장 AWT
1. AWT(Abstract Window Toolkit) 컴포넌트(Component)
가. AWT 컴포넌트 모델
AWT는 플랫폼에 독립적인 API를 제공하는 것에서 시작해서 설계되었고 아직까지는 각 플랫폼에서의 룩앤필(look and feel)을 따르고 있습니다. 예를 들어, AWT는 Button 클래스에 의해 제공되는 버튼을 위한 단지 하나의 API를 가지지만, 윈도우 95 상에서와 매킨토시에서 보이는 버튼을 서로 플랫폼에 맞게 차이가 있습니다. AWT는 플랫폼 독립적 이지만 각 플랫폼에서 특별하게 제공해 주는 구현(peer)을 사용하는 API를 제공하는 클래스(컴포넌트)들을 제공함으로써 플랫폼에 따라 서로 다르게 나타납니다. 특히, 모든 AWT 컴포넌트 클래스(Component, MenuComponent, 그리고 하위클래스)는 동등한 peer 클래스를 갖고, 모든 컴포넌트 객체는 객체의 보고 느끼는 모양 (look and feel)을 제어하는 peer 객체를 갖습니다.
Peer 객체는 해당 컴포넌트 객체가 처음으로 그려지기 전에 바로 로딩되는 느린 로딩(lazy loading)이 적용됩니다. 이러한 경우에 발생하는 주목할만한 하나의 측면 효과(side effect는 컴포넌트가 처음으로 그려지기 전까지는 그 컴포넌트의 크기가 유효하지 못하다는 것입니다.
따라서, 컨테이너는 어떤 peer도 가지지 않는데 어떤 컴포넌트를 보이지 않는(non-visible) 컨테이너에 추가하고 그 컨테이너가 처음으로 보여지기 전에, 그 컨테이너가 포함하고 있는 모든 컴포넌트들의 peer가 생성됩니다. 그러나, 만약 보이는(visible) 컨테이너에 컴포넌트를 삽입한다면, AWT가 그 컴포넌트를 위한 peer를 생성할 수 있도록 정확하게 알려주어야 합니다. 이러한 작업은 validate 메소드를 호출함으로써 하게 됩니다. 비록 현재 추가된 컴포넌트의 validate 메소드르 직접 호출할 수 있다고 하더라도, 일반적으로 컨테이너의 validate 메소드가 대신 수행됩니다. 그 이유는 컨테이너의 validate 메소드를 수행하는 것이 연쇄 작용(chain reaction)을 유발하여 컨테이너에 포함된 모든 컴포넌트들이 유효화되기(validated) 때문입니다. 예를 들어, 컴포넌트들을 Applet 객체에 추가한 후, Applet 내에 있는 모든 컴포넌트들을 위한 peer들을 생성하는 Applet의 validate 메소드를 호출합니다.
peer는 사용자의 입력 이벤트에 반응함으로써 UI 컴포넌트의 feel(간접적으로 look을)을 구현합니다. 예를 들어, 사용자가 버튼을 클릭할 때, peer는 버튼의 모양을 변하게 하고 Button 객체에 action 이벤트를전달함으로써 마우스 다운(mouse down)과 마우스 업(mouse up) 이벤트에 반응(reacting)하게 됩니다. 이론적으로, peer들은 이벤트 연결(event chain)의 끝에 위치하고 있습니다. 키가 눌리는 것과 같은 실제 이벤트(raw event)가 발생할 때, 이벤트가 발생한 컴포넌트는 먼저 이벤트를 처리하고, 그리고 나서 만약 컴포넌트의 이벤트 처리기(event handler)가 false를 리턴하였다면 컴포넌트의 컨테이너가 그 이벤트를발견하고 처리하게 됩니다. 컴포넌트 구조(hierarchy) 내에 있는 모든 컴포넌트들이 그 이벤트를 처리할 기회를 가졌고 모든 이벤트 처리기가 false를 리턴하였다면, peer가 그 이벤트를 보고 이벤트에 대한작용을 하게 됩니다.
현재 구현상에서, 위의 시나리오는 키가 눌리는 이벤트에 대해서는 올바르게 작용하지만, 마우스 이벤트에 대해서는 그렇지 않습니다. 마우스 이벤트의 경우에는, peer가 먼저 그 이벤트를 보고, 그 컴포넌트에 모든 이벤트를 보낼 필요는 없습니다. 그러나 향후 릴리즈에서는 마우스 이벤트를 키보트 이벤트와 같은 방식으로 처리할 것입니다.
peer는 가끔 키가 눌리고 마우스 클릭이 발생하는 것과 같은 실제 이벤트(raw event)로부터 고수준 이벤트 동작, 포커스 이동, 윈도우 아이콘화 등을 발생시킵니다. 이러한 보다 고수준 이벤트들은 이벤트 처리와 관련된 컴포넌트에 전달됩니다. 다음에 나오는 그림은 자바에서 제공해 주고 있는 플랫폼 독립적인 AWT 컴포넌트 클래스들의 클래스 계층도를 보여주고 있습니다.
<그림 1. 자바 컴포넌트 계층도>
위에서 보여주고 컴포넌트들은 다음과 같이 몇 가지로 분류할 수 있고, 모든 컴포넌트는 Componet 클래스를 상속하고 있습니다.
l 기본 컴포넌트: Button, Label, Choice, CheckBox, List, Canvas, ScrollBar
l 컨테이너 컴포넌트: Container, Panel, Window, Frame, Dialog, FileDialog
l 텍스트 컴포넌트: TextComponent, TextArea, TextField
<그림 2. AWT 컴포넌트의 좌표 시스템>
위의 그림은 AWT 컴포넌트들에 대한 좌표 시스템을 보여주고 있습니다. 모든 컴포넌트는 자신의 시작 위치 좌표값, 너비와 높이 값 등의 값과 자신만의 좌표 시스템을 갖습니다. 이때, 좌표 시스템의 시작좌표값은 (0,0) 입니다. 그리고, 컴포넌트의 시작 좌표값은 스크린 상의 절대 좌표값이 아닌 자신을 포함하고 있는 컴포넌트의 시작 좌표에서부터의 상대적인 크기의 좌표값을 갖습니다. 그리고 AWT 컴포넌트 모델에서의 각 좌표는 Point 객체에 의해, 크기는 Dimenstion 객체에 의해, 테두리(바운드)는 Rectangle 객체에 의해 각각 관리될 수 있습니다.
나. Component 클래스
Component 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l Rectangle bounds(): getBounds() 메소드로 바뀌었습니다.
l Rectangle getBounds(): 컴포넌트의 테두리(바운드) 정보를 얻습니다.
l Rectangle getBounds(Rectangle rv): 컴포넌트의 바운드 정보를 주어진 객체 rv에 저장하고 이 객체를 리턴합니다.
l int getX(): 컴포넌트의 시작 좌표 중 x 값을 얻습니다.
l int getY():컴포넌트의 시작 좌표 중 y 값을 얻습니다.
l Point location(): getLocation() 메소드로 바뀌었습니다.
l Point getLocation(): 컴포넌트의 현재 위치 좌표를 얻습니다.
l Point getLocation(Point rv): 컴포넌트의 현재 위치 좌표를 주어진 객체 rv에 저장하고 이 객체를 리턴합니다.
l Point getLocationOnScreen(): 컴포넌트의 스크린 상에서의 현재 위치 좌표를 얻습니다.
l int getWidth(): 컴포너트의 너비를 얻습니다.
l int getHeight(): 컴포넌트의 현재 높이를 얻습니다.
l Dimension getSize(): 컴포넌트의 크기를 얻습니다.
l Dimension getSize(Dimension rv): 컴포넌트의 크기를 얻어 rv에 저장하고 이 객체를 리턴합니다.
l void setLocation(int x, int y): 컴포넌트를 새로운 위치로 옮깁니다.
l void setLocation(Point p): 컴포넌트를 새로운 위치로 옮깁니다.
l Dimension size(): getSize() 메소드로 바뀌었습니다.
l void setSize(Dimension d): 컴포넌트의 너비와 높이를 각각 d.width와 d.height로 설정합니다.
l void setSize(int width, int height): 컴포넌트의 너비와 높이를 각각 width와 height로 설정합니다.
l void reshape(int x, int y, int width, int height): setBounds(int, int, int, int) 메소드로 바뀌었습니다.
l void resize(Dimension d): setSize(Dimension) 메소드로 바뀌었습니다.
l void resize(int width, int height): setSize(int, int) 메소드로 바뀌었습니다.
l void setBounds(int x, int y, int width, int height): 컴포넌트를 주어진 위치로 옮기고 크기를 변경합니다.
l void setBounds(Rectangle r): 컴포넌트를 주어진 위치로 옮기고 크기를 변경합니다.
l void setName(String name): 컴포넌트의 이름을 설정합니다.
l Dimension getMaximumSize(): 컴포넌트의 최대 크기를 얻습니다.
l Dimension minimumSize(): getMinimumSize() 메소드로 바뀌었습니다.
l Dimension getMinimumSize(): 컴포넌트의 최소 크기를 얻습니다.
l Dimension preferredSize(): getPreferredSize() 메소드로 바뀌었습니다.
l Dimension getPreferredSize(): 컴포넌트의 적당한 크기를 얻습니다.
l point.Component locate(int x, int y): getComponentAt(int, int) 메소드로 바뀌었습니다.
l Component getComponentAt(int x, int y): 주어진 좌표를 포함하고 있는 컴포넌트를 얻습니다.
l Component getComponentAt(Point p): 주어진 좌표를 포함하고 있는 컴포넌트를 얻습니다.
l boolean inside(int x, int y): contains(int, int) 메소드로 바뀌었습니다.
l boolean contains(int x, int y): 주어진 위치 좌표를 포함하고 있는 컴포넌트가 있는 지를 얻습니다.
l boolean contains(Point p): 주어진 위치 좌표를 포함하고 있는 컴포넌트가 있는 지를 얻습니다.
l void hide():setVisible(boolean) 메소드로 바뀌었습니다.
l boolean isDisplayable(): 이 컴포넌트가 디스플레이 가능한 지를 얻습니다.
l boolean isShowing(): 이 컴포넌트가 보여지고 있는지를 얻습니다.
l boolean isValid(): 이 컴포넌트가 유효한지를 얻습니다.
l boolean isVisible(): 컴포넌트가 보여질(visible) 수 있는지를 얻습니다.
l void layout(): doLayout() 메소드로 바뀌었습니다.
l void setVisible(boolean b): 컴포넌트를 보이거나 보이지 않게 설정합니다.
l void show(): setVisible(boolean) 메소드로 바뀌었습니다.
l void show(boolean b): setVisible(boolean) 메소드로 바뀌었습니다.
l void invalidate(): 컴포넌트를 무효화 합니다.
l void validate(): 이 컴포넌트가 유효한(valid) 레이아웃을 갖도록 만듭니다.
지금부터는 AWT에서 제공해주는 각 컴포넌트들에 대한 사용법에 대해 살펴보도록 하겠습니다. 먼저, Point 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l int x: x 좌표값을 나타냅니다.
l int y: y 좌표값을 나타냅니다.
l Point():좌표값을 저장할 객체를 생성하고 초기값은 (0,0)입니다.
l Point(int x, int y): 좌표값을 저장할 객체를 생성하고 초기값은 (x,y)입니다.
l Point(Point p): 좌표값을 저장할 객체를 생성하고 초기값은 p의 값입니다.
l Point getLocation(): 좌표값을 얻습니다.
l double getX(): 부동소수형 x좌표를 얻습니다.
l double getY(): 부동소수형 y좌표를 얻습니다.
l void move(int x, int y): 주어진 좌표로 위치를 이동합니다.
l void setLocation(double x, double y): 주어진 부동소수형 좌표로 이동합니다.
l void setLocation(int x, int y): 주어진 좌표로 이동합니다.
l void setLocation(Point p): 주어진 좌표로 이동합니다.
l void translate(int dx, int dy): 좌표를 (x + dx, y + dy)로 이동합니다.
Dimension 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l int height: 높이를 얻습니다.
l int width: 너비를 얻습니다.
l Dimension(): 너비와 높이가 0인 Dimension객체를 생성합니다.
l Dimension(Dimension d): 주어진 너비와 높이를 갖는 Dimension객체를 생성합니다.
l Dimension(int width, int height): 주어진 너비와 높이를 갖는 Dimension객체를 생성합니다.
l double getHeight (): 부동소수형 높이를 얻습니다.
l double getWidth (): 부동소수형 너비를 얻습니다.
l Dimension getSize(): 크기를 얻습니다.
l void setSize(Dimension d): 주어진 크기로 설정합니다.
l void setSize(double width, double height): 주어진 부동소수형 크기로 설정합니다.
l void setSize(int width, int height): 주어진 크기로 설정합니다.
Rectangle 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l int x: x 좌표값을 나타냅니다.
l int y: y 좌표값을 나타냅니다.
l int height: 높이를 얻습니다.
l int width: 너비를 얻습니다.
l boolean contains(int X, int Y, int W, int H), boolean contains(Rectangle r): 주어진 위치(X, Y)와 크기(W, H)에 해당하는 사각 영역을 포함하고 있는 지를 얻습니다.
l boolean contains(Point p): 주어진 점을 포함하는 지를 검사합니다.
l Rectangle getBounds(): 바운드를 얻습니다.
l void reshape(int x, int y, int width, int height): setBounds(int, int, int, int) 메소드로 바뀌었습니다.
l void setBounds(int x, int y, int width, int height): 주어진 값으로 바운드를 변경합니다.
l void setBounds(Rectangle r): 주어진 값으로 바운드를 바꿉니다.
다. 레이블(Label) 컴포넌트
Label 클래스는 프로그램의 GUI에 선택되지 않는 텍스트를 넣기 쉽도록 해 줍니다. 레이블 컴포넌트는 기본적으로 왼쪽 정렬한다. 물론, 사용자가 정렬 방식을 결정할 수 있는데, 다음과 같은 세 가지의 정렬 방식을 Label 클래스의 객체 생성자 또는 setAlignment 메소드를 이용하여 설정해 주면 됩니다.
l 왼쪽 정렬: Label.LEFT
l 가운데 정렬: Label.CENTER
l 오른쪽 정렬: Label.RIGHT
또한, 모든 다른 컴포넌트에서처럼, 레이블의 색깔과 폰트를 바꿀 수 있습니다. 폰트에 대한 자세한 내용은 나중에 폰트에 대해서 설명할 때, 자세히 다루기로 하겠습니다.
다음에 나오는 자바 프로그램은 레이블을 사용하는 방법에 대하여 간단하게 보여주는 예제입니다.
import java.awt.*; class LabelTest extends Frame { public LabelTest() { setLayout(new FlowLayout()); Label label1 = new Label(); label1.setText("Left"); label1.setSize(50, 25); label1.setBackground(Color.cyan); Label label2 = new Label("Center"); label2.setAlignment(Label.CENTER); label2.setSize(50, 25); label2.setBackground(Color.yellow); Label label3 = new Label("Right", Label.RIGHT); label3.setSize(50, 25); label3.setBackground(Color.green); add(label1); add(label2); add(label3); } public static void main(String args[]) { LabelTest f = new LabelTest(); f.setSize(200, 60); // pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java LabelTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 1. LabelTest.java>
레이블 컴포넌트가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l static int CENTER: 가운데 정렬
l static int LEFT: 왼쪽 정렬
l static int RIGHT: 오른쪽 정렬
l Label(): 레이블을 생성합니다.
l Label(String text): 주어진 이름의 레이블을 생성하고, 기본적으로 왼쪽 정렬합니다.
l Label(String text, int alignment): 주어진 이름의 레이블을 생성하고, 주어진 정렬 방식으로 정렬합니다.
l int getAlignment(): 현재 정렬 방식을 얻습니다.
l String getText(): 레이블의 텍스트를 얻습니다.
l void setAlignment(int alignment): 정렬 방식을 설정합니다.
l void setText(String text): 레이블의 텍스트를 주어진 텍스트로 설정합니다.
라. 버튼(Button) 컴포넌트
Button 클래스는 디폴트 버튼을 구현하도록 해 주고 있습니다. 버튼은 사용자가 버튼을 클릭할 때, action 이벤트를 생성하는 간단한 컨트롤입니다. 버튼은 다음과 같은 속성을 갖고 있습니다.
l 폰트(font)
l 텍스트(text)
l 전경색(foreground)
l 배경색(background)
l 버튼의 상태(활성-enabled/비활성-disabled)
다음에 나오는 예제는 자바에서 버튼을 보여주기 위한 간단한 예제입니다.
import java.awt.*; class ButtonTest extends Frame { Button b1, b2, b3; public ButtonTest() { setLayout(new FlowLayout()); b1 = new Button(); b1.setLabel("Button"); b1.setBackground(Color.blue); b1.setForeground(Color.yellow); b2 = new Button("Button"); b3 = new Button("Button"); b3.setEnabled(false); add(b1); add(b2); add(b3); } public static void main(String args[]) { ButtonTest f = new ButtonTest(); f.pack(); // setSize(200, 60); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java ButtonTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 2. ButtonTest.java>
이러한 버튼 컴포넌트가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l public Button(): 레이블 없는 버튼을 생성합니다.
l public Button(String label): 주어진 레이블의 버튼을 생성합니다.
l public String getLabel(): 이 버튼의 레이블을 얻습니다.
l public void setLabel(String label): 이 버튼의 레이블을 주어진 문자열로 설정합니다.
마. 체크박스(Checkbox) 컴포넌트
Checkbox 클래스는 "on" 또는 "off" 둘 중의 하나의 상태를 가지는 두 상태(two-state) 버튼이라 할 수 있는 체크박스를 가능하도록 해 줍니다. 사용자가 체크박스를 클릭하면, 체크박스의 상태는 변하게 되고,이 때 action 이벤트를 발생시킵니다. 체크박스와 마찬가지로 사용자가 아이템을 선택할 수 있도록 하는 컴포넌트는 선택 컴포넌트, 리스트 컴포넌트, 그리고 메뉴 컴포넌트 등입니다.
만약, 여러 개의 체크박스들 중 하나만 선택("on")될 수 있도록 체크박스들을 그룹으로 관리하고자 한다면, 체크박스의 상태를 체크하여 하나만 선택될 수 있도록 체크박스 그룹(CheckboxGroup 객체)에 추가해 주면 됩니다. 이 때, 체크박스는 라디오 버튼(radio button)과 같은 역할을 하게 됩니다.
다음에 나오는 예제 프로그램은 위에서 설명한 두 가지 형태의 체크박스를 테스트 할 수 있도록 해 주는 자바 프로그램입니다.
import java.awt.*; class CheckboxTest extends Frame { public CheckboxTest() { Panel p1, p2; Checkbox cb1, cb2, cb3; Checkbox cb4, cb5, cb6; CheckboxGroup cbg; setLayout(new FlowLayout()); cb1 = new Checkbox(); cb1.setLabel("Checkbox 1"); cb2 = new Checkbox("Checkbox 2"); cb3 = new Checkbox("Checkbox 3"); cb3.setState(true); add(cb1); add(cb2); add(cb3); cbg = new CheckboxGroup(); add(new Checkbox("Checkbox 4", cbg, false)); add(new Checkbox("Checkbox 5", cbg, false)); add(new Checkbox("Checkbox 6", cbg, false)); } public static void main(String args[]) { CheckboxTest f = new CheckboxTest(); f.setSize(350, 90); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java CheckboxTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 3. CheckboxTest.java>
위의 예에서는 두 그룹의 체크박스가 있습니다. 먼저, 위 줄에 있는 세 개의 체크박스는 서로 독립적으로 선택될 수 있는 체크박스입니다. 이들은 아래 줄에 있는 세 개의 체크박스와 체크박스 그룹에 속하지 않았다는 것 때문에 구별됩니다. 아래의 세 개의 체크박스는 체크박스를 그룹으로 관리하여 그룹에 속한 체크박스 중 하나만 선택되도록 해 주는 체크박스 그룹에 의해 관리되어 집니다. 이들의 두 그룹의 체크박스는 그 외형상에서도 차이가 납니다. 먼저, 위 줄의 체크박스는 일반적인 체크박스의 외형을 취하고 있고, 아랫 줄의 체크박스들은 라디오 버튼의 외형을 취하고 있다는 것입니다.
이러한 Checkbox 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Checkbox(): 레이블이 없는 체크박스를 생성합니다.
l Checkbox(String label): 주어진 레이블의 체크박스를 생성합니다.
l Checkbox(String label, boolean state): 주어진 레이블의 체크박스를 생성하며, 체크박스의 초기 선택 여부를 설정합니다.
l Checkbox(String label, boolean state, CheckboxGroup group): 주어진 레이블의 체크박스를 생성하며, 체크박스의 초기 선택 여부를 설정하고, 체크박스 그룹을 설정합니다.
l Checkbox(String label, CheckboxGroup group, boolean state): 주어진 레이블의 체크박스를 생성하며, 체크박스의 초기 선택 여부를 설정하고, 체크박스 그룹을 설정합니다.
l String getLabel(): 체크박스의 레이블을 구합니다.
l void setLabel(String label): 체크박스의 레이블을 설정합니다.
l boolean getState(): 체크박스의 상태가 "on" 또는 "off" 상태인지를 얻습니다.
l void setState(boolean state): 체크박스의 상태를 설정합니다.
l CheckboxGroup getCheckboxGroup(): 설정된 체크박스 그룹을 얻습니다.
l void setCheckboxGroup(CheckboxGroup g): 체크박스 그룹을 설정합니다.
CheckboxGroup 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l CheckboxGroup(): 체크박스 그룹 객체를 생성합니다.
l Checkbox getCurrent(): getSelectedCheckbox()으로 바뀌었습니다.
l Checkbox getSelectedCheckbox(): 체크박스 그룹에 속한 체크박스 중, 현재 선택된 체크박스를 얻습니다.
l void setCurrent(Checkbox box): setSelectedCheckbox(Checkbox)으로 바뀌었습니다.
l void setSelectedCheckbox(Checkbox box): 현재 주어진 체크박스가 선택되도록 설정합니다.
l
바. 선택(Choice) 컴포넌트
Choice 클래스는 메뉴와 비슷한 선택(choice) 리스트이고, 서로 구별된 버튼에 의해서 참조됩니다. 사용자는 메뉴를 나타내는 버튼을 누른 후, 아이템 중 하나를 선택합니다. 사용자가 하나의 아이템을 선택하면, 선택 컴포넌트는 action 이벤트를 발생시킵니다. 선택 컴포넌트는 제한된 공간에 몇 개의 아이템들을 디스플레이 하기를 원하면서도, 그 아이템 모두를 동시에 보여줄 필요가 없을 경우 유용합니다.이러한 선택 컴포넌트를 팝업 리스트(pop-up list)라 불리기도 합니다. 선택 컴포넌트는 체크박스 컴포넌트, 리스트 컴포넌트, 메뉴 컴포넌트 등과 같이 여러 개의 메뉴를 제공해 줍니다.
다음에 나오는 예제는 선택 컴포넌트를 사용하는 간단한 예를 보여주고 있습니다.
import java.awt.*; class ChoiceTest extends Frame { public ChoiceTest() { Choice choice; setLayout(new FlowLayout()); choice = new Choice(); choice.addItem("Winodws 95"); choice.addItem("Winodws 98"); choice.addItem("Winodws NT"); choice.addItem("Solaris"); choice.addItem("Machintosh"); add(choice); } public static void main(String args[]) { ChoiceTest f = new ChoiceTest(); f.setSize(100, 150); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java ChoiceTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 4. ChoiceTest.java>
처음에는 실행결과의 왼쪽과 같이 제한된 영역 내에 현재 선택된 아이템만을 보여주고, 사용자가 다른 아이템을 선택하기 위해 메뉴 버튼을 누르게 되면 오른쪽 실행결과와 같이 모든 아이템을 보여주어그 중 하나의 아이템을 선택할 수 있도록 합니다.
Choice 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Choice(): 선택 메뉴를 생성합니다.
l void add(String item): 아이템을 추가합니다.
l void addItem(String item): 아이템을 추가합니다.
l int countItems(): getItemCount()로 바뀌었습니다.
l int getItemCount(): 아이템의 개수를 얻습니다.
l String getItem(int index): 주어진 인덱스에 해당하는 아이템을 얻습니다.
l int getSelectedIndex(): 선택된 아이템의 인덱스를 얻습니다.
l String getSelectedItem(): 선택된 아이템의 이름을 얻습니다.
l void insert(String item, int index): 주어진 이름의 아이템을 주어진 인덱스에 추가합니다.
l void remove(int position): 주어진 위치의 아이템을 제거합니다.
l void remove(String item): 주어진 이름의 아이템을 제거합니다.
l void removeAll(): 선택 메뉴에 있는 모든 아이템을 제거합니다.
l void select(int pos): 주어진 위치의 아이템이 선택되도록 합니다.
l void select(String str): 주어진 이름의 아이템이 선택되도록 합니다.
사. 리스트(List) 컴포넌트
List 클래스는 선택가능한 텍스트 아이템들을 각 라인에 하나씩 보여주는 스크롤 가능한 공간을 제공해 줍니다. 일반적으로, 사용자는 하나의 아이템을 클릭함으로써 선택하고, 아이템을 더블 클릭하거나리턴하면 action 이벤트가 발생합니다. 또한, 리스트 컴포넌트는 동시에 여러 개를 선택하거나 또는 단지 하나를 선택할 수 있도록 합니다. 앞에서도 살펴본 것과 같이, 여러 개를 선택할 수 있도록 하는 컴포넌트에는 체크박스 컴포넌트, 선택 컴포넌트, 메뉴 컴포넌트 등의 컴포넌트들이 있습니다. 다음은 리스트 컴포넌트를 사용하는 예를 보여주는 자바 프로그램입니다.
import java.awt.*; class ListTest extends Frame { public ListTest() { setLayout(new FlowLayout()); List os, unix; os = new List(3, true); os.add("Winodws 95"); os.add("Winodws 98"); os.add("Winodws NT"); os.add("Solaris"); os.add("Machintosh"); unix = new List(); unix.add("Solaris"); unix.add("Linux"); unix.add("BSD"); unix.add("Mach"); unix.add("System V"); unix.add("Multics"); unix.add("OS/360"); add(os); add(unix); } public static void main(String args[]) { ListTest f = new ListTest(); f.pack(); // f.setSize(200, 60); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java ListTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 5. ListTest.java>
위의 자바 프로그램에서는 두 개의 리스트 컴포넌트를 보여주고 있습니다. 왼쪽에 보이는 리스트 컴포넌트는 각 아이템을 선택함으로써, 여러 개의 아이템을 선택할 수 있지만, 오른쪽에 보이는 리스트 컴포넌트는 단 하나의 아이템만 선택하도록 설정되어 있기 때문에 하나의 아이템만을 선택할 수 있습니다.
List 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l List(): 스크롤 가능한 리스트 컴포넌트를 생성합니다.
l List(int rows): 주어진 개수만큼의 라인을 보이게 하는 스크롤 가능한 리스트 컴포넌트를 생성합니다.
l List(int rows, boolean multipleMode): 주어진 개수만큼의 라인을 보이게 하는 스크롤 가능한 리스트 컴포넌트를 생성하면서, 여러 개의 아이템을 동시에 선택가능한지 여부를 설정합니다.
l void add(String item): 주어진 이름의 아이템을 추가합니다.
l void add(String item, int index): 주어진 이름의 아이템을 해당 인덱스에 추가합니다.
l void addItem(String item): add(String) 메소드로 바뀌었습니다.
l void addItem(String item, int index): add(String, int) 메소드로 바뀌었습니다.
l boolean allowsMultipleSelections(): isMultipleMode() 메소드로 바뀌었습니다.
l void clear(): removeAll() 메소드로 바뀌었습니다.
l int countItems(): getItemCount() 메소드로 바뀌었습니다.
l void delItem(int position): remove(String) 메소드와 remove(int) 메소드로 바뀌었습니다.
l void delItems(int start, int end): 현실적으로 사용되지 않으므로 private 권한으로 바꾸었습니다.
l void deselect(int index): 주어진 인덱스의 아이템을 선택 해제 합니다.
l String getItem(int index): 주어진 인덱스의 아이템을 얻습니다.
l int getItemCount(): 리스트 내의 아이템들의 개수를 얻습니다.
l String[] getItems(): 리스트 내의 아이템들의 배열을 얻습니다.
l int getRows(): 리스트에서 보이는 아이템의 개수를 얻습니다.
l int getSelectedIndex(): 선택된 아이템의 개수를 얻습니다.
l int[] getSelectedIndexes(): 선택된 아이템들의 인덱스 배열을 얻습니다.
l String getSelectedItem(): 선택된 아이템을 배열을 얻습니다.
l String[] getSelectedItems(): 선택된 아이템들의 배열을 얻습니다.
l Object[] getSelectedObjects():선택된 아이템들을 Object 객체 배열로 얻습니다.
l int getVisibleIndex(): makeVisible 메소드에 의해 마지막으로 보여진 아이템의 인덱스를 얻습니다.
l boolean isIndexSelected(int index): 인덱스에 해당하는 아이템이 선택되었는지 여부를 얻습니다.
l boolean isMultipleMode(): 여러 개의 아이템을 선택가능한지 여부를 얻습니다.
l boolean isSelected(int index): isIndexSelected(int) 메소드로 바뀌었습니다.
l void makeVisible(int index): 주어진 인덱스에 해당하는 아이템을 보이게 합니다.
l void remove(int position): 주어진 위치의 아이템을 제거합니다.
l void remove(String item): 주어진 이름의 아이템을 제거합니다.
l void removeAll(): 모든 아이템을 제거합니다.
l void replaceItem(String newValue, int index): 주어진 이덱스에 해당하는 아이템을 새로운 이름으로 변경합니다.
l void select(int index): 인덱스에 해당하는 아이템을 선택합니다.
l void setMultipleMode(boolean b): 여러 개의 아이템을 선택가능 하도록 설정합니다.
l void setMultipleSelections(boolean b): setMultipleMode(boolean) 메소드로 바뀌없습니다.
아. 스크롤바(Scrollbar) 컴포넌트
스크롤바는 다음과 같이 두 가지 목적으로 사용할 수 있습니다.
l 먼저, 스크롤바는 사용자가 값을 설정하기 위해 조작하는 슬라이더처럼 사용될 수 있습니다.
l 다음으로, 일반적으로 사용하는 수평 또는 수직 스크롤바와 같은 목적으로 사용할 수 있습니다. 이러한 스크롤바는 실제 보여지는 영역을 설정할 수 있도록 해 줍니다. 예를 들어, 이미지 뷰를 통해 이미지를 볼 때 스크롤바를 움직여 보이는 부분을 조정한다거나, 또는 텍스트 편집기를 이용하여 문서를 편집할 때 현재 보이는 문서의 부분을 조정한다거나 하는 등의 작업을 할 수 있습니다.
스크롤바 컴포넌트를 사용하기 위해서 Scrollbar 객체를 생성하면 되는데, 객체 생성자를 이용하여 또는 setValues 메소드를 이용하여 다음과 같은 스크롤바 속성값을 설정할 수 있습니다. 다음에 나오는 자바 프로그램은 스크롤바를 사용하기 위한 간단한 예를 보여주고 있습니다.
import java.awt.*; class ScrollbarTest extends Frame { public ScrollbarTest() { Panel p; Scrollbar vSlider, hSlider, slider; vSlider = new Scrollbar(Scrollbar.VERTICAL, 0, 1, 0, 255); add("East", vSlider); hSlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 4, 0, 100); add("South", hSlider); slider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 10, 0, 100); add(slider); } public static void main(String args[]) { ScrollbarTest f = new ScrollbarTest(); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java ScrollbarTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 6. ScrollbarTest.java>
스클롤바의 상태를 유지하기 위해, Scrollbar 클래스는 다음과 같은 속성을 제공해 주고 있습니다.
Property | Description | Default Value |
orientation | 스크롤바의 방향성을 나타냅니다. Scrollbar.VERTICAL 또는Scrollbar.HORIZONTAL | Scrollbar.VERTICAL |
value | 스크롤바 포인터(bubble)의 위치를 | 0 |
minimum | 스크롤바의 최소값 | 0 |
maximum | 스크롤바의 최대값 | 100 |
unit increment | Line Up 또는 Line Down 키가 눌리거나또는 스크롤바의 양쪽 끝 방향 버튼이 눌렸을 때, 값의 변환량 | 1 |
block increment | Page Up 또는 Page Down 키가 눌리거나 또는 스크롤바 포인터(bubble)의 양쪽 트랙이 마우스로 클릭되었을때,값의 변환량 | 10 |
다음과 같이 스크롤바 컴포넌트를 생성할 때, 그림과 같은 스크롤바 컴포넌트가 나타나게 됩니다.
slider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 10, 0, 100);
Scrollbar 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l static int HORIZONTAL: 수평 수크롤바를 나탑냅니다.
l static int VERTICAL: 수직 수크롤바를 나탑냅니다.
l Scrollbar(): 스클롤바를 생성합니다.
l Scrollbar(int orientation): 주어진 값에 따라 수평/수직 스클롤바를 생성합니다.
l Scrollbar(int orientation, int value, int visible, int minimum, int maximum): 주어진 스크롤바의 속성 값에 해당하는 스크롤바를 생성합니다. 각 값은 다음과 같은 의미를 갖습니다.
l int orientation: 스크롤바가 수평이면 Scrollbar.HORIZONTAL으로, 스클롤바가 수직이면 Scrollbar.VERTICAL으로 설정해 주면 됩니다.
- int value: 스크롤바의 초기값을 나타냅니다. 일반적의 초기값은 0이 됩니다.
- int visible: 스크롤 가능한 영역의 보이는 부분에 대한 픽셀 단위의 크기를 나타냅니다.
- int minimum: 스크롤바가 가질 수 있는 최소값을 나타냅니다. 스크롤 영역을 설정하기 위한 스크롤바의 경우에는 이 값은 일반적으로 0이 됩니다.
- int maximum: 스크롤바가 가질 수 있는 최대값을 나타냅니다. 스크롤 영역을 설정하기 위한 스크롤바의 경우에는 이 값은 일반적으로 픽셀 단위의 width 또는 height 값이 됩니다.
l int getBlockIncrement(): 스크롤바의 블록 증가량을 얻습니다.
l int getLineIncrement(): getUnitIncrement() 메소드로 바뀌었습니다.
l int getMaximum(): 스크롤바의 최대값을 얻습니다.
l int getMinimum(): 스크롤바의 최소값을 얻습니다.
l int getOrientation(): 스클롤바의 방향성 값을 얻습니다.
l int getPageIncrement(): getBlockIncrement() 메소드로 바뀌었습니다.
l int getUnitIncrement(): 스크롤바의 단위 증가(unit increment)량을 얻습니다.
l int getValue(): 스크롤바의 현재 값을 얻습니다.
l int getVisible(): getVisibleAmount() 메소드로 바뀌었습니다.
l int getVisibleAmount(): 스크롤바의 보이는 부분의 량을 얻습니다.
l void setBlockIncrement(int v): 스크롤바의 블록 증가량을 설정합니다.
l void setLineIncrement(int v): setUnitIncrement(int) 메소드로 바뀌었습니다.
l void setMaximum(int newMaximum): 스크롤바의 최대값을 설정합니다.
l void setMinimum(int newMinimum): 스크롤바의 최소값을 설정합니다.
l void setOrientation(int orientation): 스크롤바의 방향성을 설정합니다.
l void setPageIncrement(int v): setBlockIncrement() 메소드로 바뀌었습니다.
l void setUnitIncrement(int v): 스크롤바의 단위 증가량을 설정합니다.
l void setValue(int newValue): 스크롤바의 현재 값을 설정합니다.
l void setValues(int value, int visible, int minimum, int maximum): 스크롤바의 속성 값들을 설정합니다. 속성 값들에 대해서는 객체 생성자를 참조하시기 바랍니다.
l void setVisibleAmount(int newAmount): 스크롤바의 보이는 부분의 량을 설정합니다.
자. 캔버스(Canvas) 컴포넌트
Canvas 클래스는 하위클래스에 의해 상속되어야 하며, 사용자 컴포넌트를 구현할 수 있는 방법을 제공해 줍니다. 예를 들어, 캔버스 컴포넌트에는 그래픽을 그린다거나 이미지를 그리는 등의 작업을 하는데 유용하고, 이를 위해 Canvas 클래스를 상속하여 하나의 새로운 하위클래스를 정의할 수 있습니다. 또한, 캔버스 컴포넌트를 이용하여 원형 버튼과 같은 새로운 형태의 버튼과 같은 컨트롤을 만드는데 유용하게 쓰일 수 있습니다. 왜냐하면, AWT 컴포넌트로 제공되는 컴포넌트에 대한 모양을 변화시킬 수 없기 때문에, 캔버스 컴포넌트를 상속하여 새로운 형태의 컨트롤을 생성하는 것입니다. 이 때, 다음과같은 메소드를 구현할 때, 정확하게 캔버스의 크기를 계산하도록 주의해야 합니다. 왜냐하면, 그렇지 않을 경우 캔버스 컴포넌트를 포함하는 컨테이너의 레이아웃에 따라 보이지 않을 정도로 캔버스 컴포넌트가 작게 나타날 수도 있기 때문입니다.
일반적으로, 도형을 그린다거나 이미지를 그리는 등의 그래픽 작업을 프레임 또는 패널 컴포넌트에 직접 하기 쉬운데, 자바에서는 이러한 작업을 할 수 있도록 하기 위해 캔버스 컴포넌트를 제공하고 있습니다. 아직, 그래픽 작업을 할 수 있도록 해 주는 Graphics 클래스에 대해서 다루지 않았기 때문에, 여기서는 이 정도로 넘어가기로 하겠습니다. 대신, 나중에 Graphics 클래스에 대해서 설명할 때, 캔버스 컴포넌트의 사용예를 살펴보도록 하겠습니다. 다음에 바로 살펴 보겠지만, 패널 컴포넌트는 여러 개의 컴포넌트들을 포함하면서 이들을 하나의 컴포넌트처럼 다룰 수 있도록 하기 위한 컨테이너이고, 프레임컴포넌트는 애플리케이션을 위한 프레임 윈도우를 제공합니다. 다시 말해서, 프레임은 하나의 애플리케이션을 위한 GUI 틀을 제공해 주는데, 윈도우, 보더, 그리고 메뉴바 등과 같은 기본 프레임을 제공해줍니다.
2. 컨테이너(Container) 컴포넌트
가. Container 클래스와 Inset 클래스
일반적으로 컨테이너에 컴포넌트를 삽입하기 위해 Container 클래스의 add 메소드를 이용합니다. 이 때, Container 클래스에서는 다음과 같은 형태의 add 메소드를 제공해 줍니다.
l public Insets getInsets(): 컨테이너의 테두리(border) 크기를 설정하여 가지고 있는 인셋(inset)을 얻습니다.
l public Insets insets(): getInsets() 메소드로 바뀌었습니다.
l public Component add(Component comp): 주어진 컴포넌트를 컴포넌트의 끝에 추가합니다.
l public Component add(String name, Component comp): 주어진 컴포넌트를 컴포넌트의 해당 위치에 추가합니다.
l public Component add(Component comp, int index): 주어진 컴포넌트를 해당 위치에 추가합니다. index 값이 -1이면 끝에 추가합니다.
l public void add(Component comp, Object constraints): 주어진 컴포넌트를 컨테이너의 끝에 추가합니다. 또한, 레이아웃 관리자에게 주어진 constraints 객체를 사용하여 이 컴포넌트를 추가하도록 알립니다.
l public void add(Component comp, Object constraints, int index):: 주어진 컴포넌트를 컨테이너의 주어진 위치에 추가합니다. 또한, 레이아웃 관리자에게 주어진 constraints 객체를 사용하여 이 컴포넌트를추가하도록 알립니다.
l public LayoutManager getLayout(): 레이아웃 관리자를 얻습니다.
l public void setLayout(LayoutManager mgr): 레이아웃 관리자를 설정합니다.
l public void doLayout(): 컨네이너가 레이아웃을 수행하도록 합니다. 이 메소드를 직접호출하지는 않고, 대신 validate 메소드를 호출합니다.
l public void layout():doLayout()메소드로 바뀌었습니다.
l public void invalidate(): 컨테이너무효화(invalidate)하여, 이 컨테이너는 물론 이 컨테이너에 연결된 모든 상위 컨테이너들이 레이아웃 되도록 합니다. 대신, 에 메소드는 자주 호출되므로, 빠르게 수행될 수 있도록 구현되어야 합니다.
l public void validate(): 컨테이너와 모든 하위 컴포넌트들을 유효화(validate) 합니다. AWT는 컨테이너에 컴포넌트가 추가되거나 컨테이너의 크기가 변했을 경우, 이 validate 메소드를 public Dimension getPreferredSize(): 이 컨테이너가 가져야 할 적당한 크기를 얻습니다.
l public Dimension preferredSize(): getPreferredSize() 메소드로 바뀌었습니다.
l public Dimension getMinimumSize(): 컨테이너를 위한 최소 크기를 얻습니다.
l public Dimension minimumSize(): getMinimumSize() 메소드로 바뀌었습니다.
l public Dimension getMaximumSize(): 컨테이너를 위한 최대 크기를 얻습니다.
자바에서는 컨테이너에서 테두리를 나타내기 위해 Inset 클래스를 제공해 주고 있습니다. 테두리는 레이아웃 관리자가 레이아웃을 행할 때 유용하게 사용합니다. 다시 말하자면, 컨테이너가 가진 영역 중에서 실제로 컴포넌트를 표현하거나 작업을 할 수 있는 영역은, 컨테이너 또는 컴포넌트의 영역 중에서 inset이 가리키고 있는 테두리 영역이라 할 수 있습니다. 이 때, Inset 클래스에서는 다음과 같은 변수와 메소드를 제공해 줍니다.
l int bottom: 테두리의 아래쪽 크기를 나타냅니다.
l int left: 테두리의 왼쪽 크기를 나타냅니다.
l int right: 테두리의 오른쪽 크기를 나타냅니다.
l int top: 테두리의 위쪽 크기를 나타냅니다.
l Insets(int top, int left, int bottom, int right): 주어진 각각의 크기를 갖는 inset을 생성합니다.
l String toString(): inset 객체를 문자열로 표현하여 리턴해 줍니다.
다음의 그림은 이러한 자바에서의 inset에 대해 자세히 보여주고 있습니다.
<그림 3. Inset 개념도>
나. 패널(Panel) 컴포넌트
Panel 클래스는 Container 클래스의 하위클래스로서 일반 목적으로 사용됩니다. 패널 컴포넌트는 다른 일반 컴포넌트들을 포함하여 유지시키거나, 또는 패널이 포함하고 있는 컴포넌트들에 대한 이벤트를처리하기 위한 특별한 기능을 가질 수도 있습니다. 이러한 패널 클래스의 대표적인 하위클래스는 Applet 클래스입니다.
다음에 나오는 자바 프로그램은 패널 클래스의 사용 목적을 보여주는 가장 간단한 예제입니다.
import java.awt.*; class PanelTest extends Frame { public PanelTest() { Panel p1, p2; p1 = new Panel(); p1.add(new Button("Button 1")); p1.add(new Button("Button 2")); p1.add(new Button("Button 3")); add("North", p1); p2 = new Panel(); p2.add(new Button("Button 4")); p2.add(new Button("Button 5")); p2.add(new Button("Button 6")); add("Center", p2); } public static void main(String args[]) { PanelTest f = new PanelTest(); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java PanelTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 7. PanelTest.java>
위의 자바 프로그램에서는 두 개의 패널 컴포넌트를 사용하고 있습니다. 다음에 레이아웃 관리자(Layout Manager)에 대하여 자세히 설명하겠지만, 위의 프로그램에 대해 다음에 나오는 자바 프로그램과 비교해 보기 바랍니다.
import java.awt.*; class PanelTest2 extends Frame { public PanelTest2() { Panel p2; add(new Button("Button 1")); add(new Button("Button 2")); add(new Button("Button 3")); p2 = new Panel(); p2.add(new Button("Button 4")); p2.add(new Button("Button 5")); p2.add(new Button("Button 6")); add("South", p2); } public static void main(String args[]) { PanelTest2 f = new PanelTest2(); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java PanelTest2 D:\AIIT\JAVA\Working\08> */ |
<프로그램 8. PanelTest2.java>
간단하게 설명하자면, 첫 번째 패널 테스트 프로그램에서는 프레임에 패널 컴포넌트 하나를 추가했고, 두 번째 패널 테스트 프로그램에서는 프레임에 버튼 컴포넌트 세 개를 추가했습니다. 그런데, 첫 번째 예제에서는 세 개의 버튼 모두가 나왔지만, 두 번째 예제에서는 마지막 추가한 3번 버튼만 나옵니다. 다시 말해서, 같은 위치는 하나의 컴포넌트만 추가할 수 있다는 것입니다. 그렇기 때문에 두 개 이상의 컴포넌트를 추가하고자 한다면, 이 컴포넌트들을 패널 컴포넌트에 추가하여 하나의 컴포넌트처럼 해 주어야 한다는 것입니다. 이러한 목적으로 패널 컴포넌트를 자주 사용하게 됩니다.
Panel 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같고, 대부분의 메소드는 Container 클래스와 Component 클래스의 메소드를 상속하고 있습니다.
l Panel(): 디폴트 레이아웃 관리자를 갖는 패널을 생성합니다.
l Panel(LayoutManager layout): 주어진 디폴트 레이아웃 관리자를 갖는 패널을 생성합니다.
다음에 나오는 자바 프로그램은 Panel 클래스를 상속하여 새로운 형태의 패널을 간단하게 재정의 하는 예를 보여주고 있습니다.
import java.awt.*; class FramedArea extends Panel { public FramedArea() { } public Insets getInsets() { return new Insets(4,4,5,5); } public void paint(Graphics g) { Dimension d = getSize(); Color bg = getBackground(); g.setColor(bg); g.draw3DRect(0, 0, d.width - 1, d.height - 1, true); g.draw3DRect(3, 3, d.width - 6, d.height - 6, false); } } class PanelTest3 extends Frame { public PanelTest3() { FramedArea p1, p2; p1 = new FramedArea(); p1.add(new Button("Button 1")); p1.add(new Button("Button 2")); p1.add(new Button("Button 3")); add("North", p1); p2 = new FramedArea(); p2.add(new Button("Button 4")); p2.add(new Button("Button 5")); p2.add(new Button("Button 6")); add("Center", p2); } public static void main(String args[]) { PanelTest3 f = new PanelTest3(); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java PanelTest3 D:\AIIT\JAVA\Working\08> */ |
<프로그램 9. PanelTest3.java>
다. 윈도우(Window) 컴포넌트
Window 클래스는 윈도우 컴포넌트가 갖아야 할 기본적인 기능을 제공해 주기 위한 클래스로서, Dialog 클래스와 Frame 클래스가 이 Window 클래스를 상속하여 하위클래스를 정의함으로써 하나의 독립된윈도우로 동작할 수 있도록 해 줍니다. 또한, 부모 윈도우와 자식 윈도우 간에 존재하는 종속관계를 유지하기 위해 필요로 하는 여러 가지 기능들도 제공해 주고 있습니다. 다시 말해서, 하나의 기본 윈도우(기본적으로 프레임의 형태로 나타나지만)에서 작업을 하다가 파일을 열기 위해 파일 대화 상자를 연다거나, 또는 경고 메시지를 보여주거나 또는 작업의 진행을 계속할 것인지의 여부를 묻기 위한 대화상자를 나타낼 때, 이러한 대화상자는 하나의 윈도우로 나타나게 됩니다. 이 때, 원래부터 작업을 하던 윈도우는 부모(parent 또는 owner) 윈도우로서 대화상자 윈도우는 자식(child) 윈도우로서 동작하게됩니다. 이러한 관계들을 유지시키는 기능을 하는 것이 바로 윈도우 컴포넌트입니다.
import java.awt.*; class WindowTest extends Frame { FileDialog fileDialog; Window w1, w2; public WindowTest() { MenuBar menuBar; Menu fileMenu; menuBar = new MenuBar(); setMenuBar(menuBar); fileMenu = new Menu("File"); menuBar.add(fileMenu); fileMenu.add(new MenuItem("New")); fileMenu.addSeparator(); fileMenu.add(new MenuItem("Open")); fileMenu.add(new MenuItem("Close")); menuBar.add(new Menu("Edit")); menuBar.add(new Menu("View")); menuBar.setHelpMenu(new Menu("Help")); w1 = new Window(this); w1.setLayout(new FlowLayout()); w1.add(new Button("Button 1")); w1.add(new Button("Button 2")); w1.add(new Button("Button 3")); w2 = new Window(this); Panel p = new Panel(); w2.add(p); p.add(new Button("Button 4")); p.add(new Button("Button 5")); p.add(new Button("Button 6")); } public static void main(String args[]) { WindowTest f = new WindowTest(); f.setLocation(80, 70); // pack(); f.setSize(200, 60); // pack(); f.setVisible(true); f.w2.toFront(); Window w[] = f.getOwnedWindows(); for(int i=0;i<w.length;i++) { System.out.println("Window["+i+"]: " + w[i]); } f.w1.setLocation(100,100); f.w1.setBackground(Color.cyan); f.w1.pack(); f.w1.show(); f.w2.setLocation(100,140); f.w2.setBackground(Color.green); f.w2.pack(); f.w2.show(); for(int i=0;i<w.length;i++) { System.out.println("Window["+i+"]: " + w[i]); } } } /* * Results: D:\AIIT\JAVA\Working\08>java WindowTest Window[0]: java.awt.Window[win0,0,0,0x0,invalid,hidden,layout=java.awt.FlowLayout] Window[1]: java.awt.Window[win1,0,0,0x0,invalid,hidden,layout=java.awt.BorderLayout] Window[0]: java.awt.Window[win0,100,100,197x32,layout=java.awt.FlowLayout] Window[1]: java.awt.Window[win1,100,140,197x32,layout=java.awt.BorderLayout] D:\AIIT\JAVA\Working\08> */ |
<프로그램 10. ScrollbarTest.java>
위의 프로그램을 실행한 결과와 같이, 윈도우 컴포넌트는 보더(border)와 메뉴바(menubar)를 전혀 갖지 않는 최상위(top-level) 윈도우를 나타냅니다. 그러므로, 윈도우는 생성될 때, 자신을 소유하는 부모 윈도우로서 프레임, 대화상자, 또는 다른 윈도우 중 하나를 항상 지정해 주어야 합니다. 그리고, 윈도우 컴포넌트를 생성하면 기본적으로 보이지 않는 상태가 되는데, 이 때 다음과 같은 몇 가지 작업을 해 주어야 자신이 의도한 윈도우를 볼 수 있습니다.
l 윈도우 크기를 적당하게 설정합니다. 디폴트 크기는 (0,0)이기 때문에 윈도우를 보이는(visible) 상태로 설정하더라도 보이지 않습니다.
- w1.setSize (200, 100); 또는
- w1.pack();
l 윈도우 컴포넌트가 보이는(Visible) 상태로 설정합니다. 디폴트 상태는 보이지 않는(invisible) 상태이기 때문에 보이도록 상태를 바꾸어 주어야 합니다.
- w1.setViisible(true); 또는
- w1.show();
l 윈도우 위치를 적당하게 조정합니다. 디폴트 위치는 (0,0)이고 보더가 없기 때문에 윈도우를 이동 불가능하므로, 프로그램 상에서 적당한 위치를 설정해 주어야 합니다.
- w1.setLocation(100, 100);
또는 위와 같은 작업을 프로그램 상에서 한 후에, 윈도우의 상태값이 바뀐 것을 알 수 있습니다.
윈도우 컴포넌트의 기능을 제공해 주기 위한 Window 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Frame(): 새로운 프레임을 생성하고, 초기에는 보이지 않도록 설정됩니다.
l Window(Frame owner): 주어진 프레임에 속하는 새로운 윈도우를 보이지 않는(invisible) 상태로 생성합니다.
l Window(Window owner): 주어진 윈도우에 속하는 새로운 윈도우를 보이지 않는(invisible) 상태로 생성합니다.
l void dispose(): 윈도우와 윈도우에 속한 컴포넌트들에 의해 사용되고 있는 노든 네이티브 스크린 자원들을 할당 해제합니다.
l Component getFocusOwner(): 윈도우가 활성화되어 있을 때, 현재 포커스를 가지고 있는 윈도우의 자식 컴포넌트를 얻습니다.
l InputContext getInputContext(): 윈도우의 입력 컨텍스트(Input Context)를 얻습니다.
l Locale getLocale(): 윈도우에 연결되어 있는 로케일 객체(Locale Object)를 얻습니다.
l Window[] getOwnedWindows(): 이 윈도우에 속한 모든 윈도우를 포함하는 배열을 얻습니다.
l Window getOwner(): 윈도우의 부모(parent or owner) 윈도우를 얻습니다.
l Toolkit getToolkit(): 이 프레임의 툴킷(toolkit)을 얻습니다.
l String getWarningString(): 윈도우에 디스플레이 될 경고 문자열(warning string)을 얻습니다.
l boolean isShowing(): 이 윈도우가 스크린 상에 보여지고 있는지를 얻습니다.
l void pack(): 윈도우를 적당한 크기로 조정하고 자신에 속한 컴포넌트들을 배치합니다.
l void show(): 윈도우가 보여지도록 합니다.
- void toBack(): 윈도우를 뒤로 보냅니다.
l void toFront(): 윈도우를 앞으로 가져옵니다.
라. 프레임(Frame) 컴포넌트
Frame 클래스는 애플릿과 애플리케이션에서 윈도우를 사용할 수 있도록 해 줍니다. 앞에서 살펴 본 모든 자바 프로그램들에서도 프레임을 상속하여 각 컴포넌트들을 보여주도록 했듯이, 모든 애플리케이션은 적어도 하나의 프레임을 필요로 합니다. 만약, 애플리케이션이 다른 윈도우에 종속적인 윈도우를 가지고 있다면, 두 윈도우는 부모 윈도우와 자식 윈도우의 관계를 갖게 됩니다. 자식 윈도우는 부모윈도우의 상태에 영향을 받게 되는데, 부모 윈도우가 최소화되어 아이콘 상태가 되었다면 자식 윈도우는 마찬가지로 화면상에서 사라지게 될 것이고, 부모 윈도우가 닫히게 된다면 자식 윈도우 역시 부모윈도우와 운명을 같이 하게 됩니다.
다음에 나오는 자바 프로그램은 가장 단순한 형태의 프레임을 보여주는 예제입니다.
import java.awt.*; public class FrameTest extends Frame { public static void main(String args[]) { FrameTest f = new FrameTest(); f.setTitle("Frame Test"); f.setSize(200, 100); // f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java FrameTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 11. FrameTest.java>
프레임 컴포넌트의 기능을 제공해 주기 위한 Frame 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Frame(): 새로운 프레임을 생성하고, 초기에는 보이지 않도록 설정됩니다.
l Frame(String title): 주어진 이름을 갖는 새로운 프레임을 생성하고, 초기에는 보이지 않도록 설정됩니다.
l static Frame[] getFrames(): 애플리케이션에 의해 생성된 모든 프레임을 포함하는 배열을 얻는다.
l Image getIconImage(): 프레임이 최소화 아이콘 상태일 때, 표시될 이미지를 얻는다.
l void setIconImage(Image image): 프레임이 최소화 아이콘 상태일 때, 표시할 이미지를 설정한다.
l MenuBar getMenuBar(): 프레임을 위한 메뉴바를 얻는다.
l void setMenuBar(MenuBar mb): 주어진 메뉴바로 프레임의 메뉴바를 설정한다.
l int getState(): 프레임의 상태를 얻는다.
l void setState(int state): 프레임의 상태를 설정한다.
l String getTitle(): 프렘임의 제목을 얻는다.
l void setTitle(String title): 주어진 문자열로 프레임의 제목을 설정한다.
l boolean isResizable(): 사용자에 의해 프레임의 크기가 변경가능한지를 얻는다.
l void setResizable(boolean resizable): 사용자에 의해 프레임의 크기가 변경가능한지를 설정한다.
l void remove(MenuComponent m): 주어진 메뉴바를 프레임에서 제거한다.
마. 대화상자(Dialog) 컴포넌트
자바에서는 대화상자(dialog box)를 위한 Dialog 컴포넌트를 제공해 주고 있습니다. 대화상자는 사용자들이 파일을 선택하여 오픈하는 등의 작업을 쉽게 할 수 있도록 하는 FileDialog 컴포넌트와 같은 유용한하위클래스를 만들 수 있도록 해 줍니다. 같은 Frame 클래스를 상속하는 대화상자와 윈도우의 차이점을 살펴보면, 대화상자는 윈도우에 종속적이기 때문에 그 윈도우가 닫히게 되면 대화상자도 같이 닫히게 되고, 윈도우가 최소화되어 아이콘으로 변하게 되면 대화상자는 사라지게 된다는 것입니다. 그런데, 자바 애플릿의 경우에는 이러한 대화상자를 일반적으로 사용할 수 없습니다. 나중에 애플릿에 대해서 자세히 다루겠지만, 애플릿은 Frame 클래스 또는 Window 클래스를 상속하는 것이 아니라, Panel 클래스를 상속하므로 윈도우를 가질 수 없기 때문입니다.
그러나, 애플릿이 자신의 윈도우(또는 프레임)을 가진다면, 그 윈도우에 종속된 대화상자를 가질 수 있겠지요. 이러한 이유로, 다음에 나오는 애플릿은 대와상자를 갖는 윈도우를 갖는 버튼들로 구성되어있습니다.
대화상자는 모달(modal)일 수 있습니다. 모달 대화상자는 대화상자가 닫힐 때까지 대화상자 이외의 다른 작업을 할 수 없게 합니다. 대화상자는 디폴트로 모달이 아니므로(non-model 또느 modal-less), 대화상자 이외의 윈도우 등에서 작업을 할 수 있습니다.
import java.awt.*; class TitleBox extends Dialog { TextField field; Button setButton; Frame parent; TitleBox(Frame dw, String title) { super(dw, title, false); parent = dw; setLayout(new FlowLayout()); field = new TextField(20); setButton = new Button("SET"); add(field); add(setButton); pack(); } public boolean action(Event event, Object arg) { if ( (event.target == setButton) | (event.target instanceof TextField)) { parent.setTitle(field.getText()); } field.selectAll(); setVisible(false); return true; } } class DialogTest extends Frame { public DialogTest() { TitleBox titleBox = new TitleBox(this, "Input you title..."); setLayout(new FlowLayout()); titleBox.show(); } public static void main(String args[]) { DialogTest f = new DialogTest(); f.setSize(250, 100); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java DialogTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 12. DialogTest.java>
위의 자바 프로그램에서는 하나의 대화상자를 열어 문자열을 입력받은 후 "SET" 버튼을 누르면, 대화상자가 종속된 윈도우의 타이틀 바(title bar)의 제목을 입려된 문자열로 바꾸고, 대화상자를 닫는 작업을합니다. 이 때, 버튼이 눌렸을 때, 이 이벤트를 받아 처리하기 위한 action 메소드가 있는데, 이에 대해서는 나중에 자세히 설명하기로 하겠습니다. 위의 실행화면을 살펴보면, 대화상자를 종료하기 전에는 윈도우의 타이틀 바에 아무 제목도 없지만, 대화상자가 닫힌 후에는 타이틀 바의 내용이 바뀌게 된 것을 볼 수 있습니다.
대화상자 컴포넌트의 기능을 제공해 주기 위한 Dialog 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Dialog(Dialog owner), Dialog(Frame owner): 이름이 없고, 주어진 프레임 또는 대화상자에 종속되고, non-modal인 대화상자를 생성하는데, 초기에는 보이지 않도록 설정됩니다.
l Dialog(Frame owner, boolean modal): 이름이 없고, 주어진 프레임에 종속되고, 주어진 modal의 대화상자를 생성하는데, 초기에는 보이지 않도록 설정됩니다.
l Dialog(Dialog owner, String title), Dialog(Frame owner, String title): 주어진 이름을 갖고, 주어진 프레임 또는 대화상자에 종속되고, non-modal인 대화상자를 생성하는데, 초기에는 보이지 않도록 설정됩니다.
l Dialog(Dialog owner, String title, boolean modal), Dialog(Frame owner, String title, boolean modal): 주어진 이름을 갖고, 주어진 프레임 또는 대화상자에 종속되고, 주어진 modal을 갖는 대화상자를 생성하는데,초기에는 보이지 않도록 설정됩니다.
l
l String getTitle(): 대화상자의 제목을 얻습니다.
l boolean isModal(): 대화상자가 modal인지 여부를 얻습니다.
l boolean isResizable(): 대화상자가 사용자에 의해 크기 변화가 가능한지 여부를 얻습니다.
l void setModal(boolean b): 대화상자의 modal을 주엊니 값으로 설정합니다.
l void setResizable(boolean resizable): 대화상자의 크기변화 여부를 주어진 값으로 설정합니다.
l void setTitle(String title): 대화상자의 제목을 설정합니다.
l void show(): 대화상자가 보여지게 만듭니다.
바. 파일 대화상자(FileDialog) 컴포넌트
FileDialog 클래스는 Dialog 클래스를 상속하는 하위클래스입니다. 파일 대화상자 컴포넌트의 역할은 읽기 또는 쓰기를 위한 파일을 선택하는 작업을 사용자들이 보다 쉽게 할 수 있도록 해 준다는 것입니다.대부분의 윈도우 응용프로그램에서 파일을 읽거나 쓰려고 할 때 나타나는 대화상자와 같은 역할을 하는 것입니다.
다음에 나오는 자바 프로그램은 파일 대화상자를 사용하는 간단한 예를 보여주는 프로그램입니다.
import java.io.*; import java.awt.*; class FileDialogTest extends Frame { FileDialog fromDialog, toDialog; public FileDialogTest() { super("File copy"); fromDialog = new FileDialog(this, "Copy from", FileDialog.LOAD); toDialog = new FileDialog(this, "Copy to", FileDialog.SAVE); } public void copyFile() { FileInputStream in; FileOutputStream out; int count; byte buf[] = new byte[128]; fromDialog.setDirectory(""); fromDialog.setFile("Test.java"); fromDialog.show(); if(fromDialog.getFile() == null) { System.out.println("Source file i'snt selected..."); return; } toDialog.setDirectory(""); toDialog.setFile("Noname.txt"); toDialog.show(); if(toDialog.getFile() == null) { System.out.println("Destination file i'snt selected..."); return; } System.out.println("copy " + fromDialog.getFile() + " to " + toDialog.getFile()); try { in = new FileInputStream(fromDialog.getFile()); out = new FileOutputStream(toDialog.getFile()); do { count = in.read(buf); if(count > 0) { out.write(buf, 0, count); } } while(count > 0); in.close(); out.close(); } catch(IOException e) { System.out.println("IOException"); } } public static void main(String args[]) { FileDialogTest f = new FileDialogTest(); f.pack(); f.setVisible(true); f.copyFile(); System.exit(0); } } /* * Results: D:\AIIT\JAVA\Working\08>java FileDialogTest copy FileDialogTest.dat to FileDialogTest.dst D:\AIIT\JAVA\Working\08>type FileDialogTest.dst The FileDialog class displays a dialog window from which the user can select a file. Since it is a modal dialog, when the application calls its show method to display the dialog, it blocks the rest of the application until the user has chosen a file. D:\AIIT\JAVA\Working\08>type FileDialogTest.dat The FileDialog class displays a dialog window from which the user can select a file. Since it is a modal dialog, when the application calls its show method to display the dialog, it blocks the rest of the application until the user has chosen a file. D:\AIIT\JAVA\Working\08> */ |
<프로그램 13. FileDialogTest.java>
위의 예에서는 두 개의 파일 대화상자를 생성하여 사용하고 있습니다. 다시 말해서, 파일을 복사하기 위하여 원본 파일의 이름을 읽기용으로 선택하기 위한 파일 대화상자와 복사하여 새로 생성할 파일의이름을 쓰기용으로 선택하기 위한 파일 대화상자입니다. 두 개의 파일을 각각의 목적에 맞게 선택하였을 경우, 파일이 제대로 선택되었는지를 확인하기 위하여 getFile 메소드의 결과가 null 인지 여부를 검사합니다. 만약, 그 결과가 null일 경우, 파일이 제대로 선택된 것이 아니기 때문입니다.
파일 대화상자 컴포넌트의 기능을 제공해 주기 위한 FileDialog 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l static int LOAD: 읽기 파일을 고르기 위해 파일 대화상자 윈도우를 사용한다는 것을 가리킵니다.
l static int SAVE: 쓰기 파일을 고르기 위해 파일 대화상자 윈도우를 사용한다는 것을 가리킵니다.
l FileDialog(Frame parent): 주어진 프레임에 속한 파일 적재용(loading a file) 대화상자를 생성합니다.
l FileDialog(Frame parent, String title): 주어진 프레임에 속하고 주어진 이름을 갖는 파일 적재용(loading a file) 대화상자를 생성합니다.
l FileDialog(Frame parent, String title, int mode): 주어진 프레임에 속하고 주어진 이름을 갖고 주어진 모드(loading/saving)의 파일 대화상자를 생성합니다.
l String getDirectory(): 파일 대화상자의 디렉토리를 얻습니다.
l String getFile(): 파일 대화상자에 의해 선택된 파일을 얻습니다.
l FilenameFilter getFilenameFilter(): 파일 대화상자의 파일 이름 필터를 얻습니다.
l int getMode(): 파일 대화상자의 용도가 읽기용(loading)인지 쓰기용(saving)인지를 얻습니다.
l void setDirectory(String dir): 파일 대화상자의 디렉토리를 설정합니다.
l void setFile(String file): 파일 대화상자의 파일을 설정합니다.
l void setFilenameFilter(FilenameFilter filter): 파일 대화상자의 파일 이름 필터를 설정합니다.
l void setMode(int mode): 파일 대화상자의 용도(mode)를 설정합니다.
3. 텍스트 컴포넌트(Text Component)
가. 텍스트 필드 컴포넌트와 텍스트 영역 컴포넌트
TextArea 클래스와 TextField 클래스는 선택가능한 텍스트를 디스플레이 해 주고, 선택적으로 사용자가 텍스트를 편집할 수 있도록 해 줍니다. TextArea 클래스와 TextField 클래스를 상속하는 하위클래스를이용하여 입력할 때 발생하는 에러를 검사할 수도 있습니다. 다른 포넌트와 같이, 텍스트 영역 컴포넌트와 텍스트 필드 컴포넌트의 전경색, 배경색, 컬러, 폰트 등을 설정할 수 있지만, 외형상 나타나는 모양을 변화시킬 수는 없습니다. TextArea 클래스와 TextField 클래스는 TextComponent 클래스의 하위클래스로서, 텍스트 선택을 얻거나 설정하고, 텍스트 편집을 가능하게 하거나 불가능하게 하기도 하고, 선택된 텍스트 또는 모든 텍스트를 얻고, 마지막으로 텍스트를 설정할 수 있도록 해 주는 메소드들을 TextComponent 클래스로부터 상속하고 있습니다.
아래에 있는 자바 프로그램은 텍스트 필드 컴포넌트와 텍스트 영역 컴포넌트에 대한 간단한 사용을 보여주고 있습니다.
import java.awt.*; class TextComponentTest extends Frame { public TextComponentTest() { Panel p1, p2; TextField tf1, tf2, tf3, tf4; TextArea textArea; p1 = new Panel(); add("North", p1); tf1 = new TextField(); tf2 = new TextField("", 30); tf2.setEditable(false); p1.add(tf1); p1.add(tf2); textArea = new TextArea(5, 30); textArea.setText("Hello, World!\n"); textArea.selectAll(); textArea.append("Hello, Java!\n"); textArea.insert("Hello!\n", 0); add("Center", textArea); p2 = new Panel(); add("South", p2); tf3 = new TextField("Hello, World!"); tf3.select(1, 5); tf4 = new TextField("Hello, World!", 30); tf4.selectAll(); p2.add(tf3); p2.add(tf4); System.out.println(" tf1.getSelectedText(): " + tf1.getSelectedText()); System.out.println(" tf2.getSelectedText(): " + tf2.getSelectedText()); System.out.println(" tf3.getSelectedText(): " + tf3.getSelectedText()); System.out.println(" tf4.getSelectedText(): " + tf4.getSelectedText()); System.out.println("textArea.getSelectedText(): " + textArea.getSelectedText()); } public static void main(String args[]) { TextComponentTest f = new TextComponentTest(); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java TextComponentTest tf1.getSelectedText(): tf2.getSelectedText(): tf3.getSelectedText(): ello tf4.getSelectedText(): Hello, World! textArea.getSelectedText(): Hello! Hello, D:\AIIT\JAVA\Working\08> */ |
<프로그램 14. TextComponentTest.java>
위의 자바 프로그램을 테스트 해 보면, 두 번째 텍스트 필드(TextField) 컴포넌트는 편집 할 수 없는 것을 알 수 있을 것입니다. 그리고, 텍스트 영역(TextArea) 컴포넌트에 하나의 텍스트 라인을 삽입하고자 할때는 텍스트의 끝에 '\n'을 추가해 주어야 합니다. 그리고, 마지막으로 텍스트 영역에서 처음에 "Hello, World!" 텍스트를 설정한 후, seleceAll 메소드를 실행하고, 그 후에 차례데로 "Hello, Java!" 텍스트와 "Hello!"텍스트를 삽입하였는데, 선택 영역이 두 줄로 바뀌었지요. 이는 기존의 선택영역을 그대로 유지하기 때문에 그렇습니다. 다시 말해서, 처음의 선택영역 "Hello, World!"가 있던 부분을 그대로 유지하게 되는데, 마지막에 첫 줄에 "Hello!\n"가 삽입되었으므로, "Hello, World!" 만큼의 공간인 "Hello!\nHello, " 부분을 선택영역으로 유지하게 되는데, 이 때 화면상에 나타날 때는 '\n' 문자의 영향 때문에 다음 줄로 나타나보이게 되는 것입니다.
TextComponent 클래스, TextField 클래스, 그리고 TextArea 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 각각 다음과 같습니다.
나. TextComponent 클래스
TextComponent 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 각각 다음과 같습니다.
l int getCaretPosition(): 텍스트 삽입 캐럿(I자 형태)의 위치를 얻습니다.
l String getSelectedText(): 선택 영역의 텍스트를 얻습니다.
l int getSelectionEnd(): 선택된 텍스트의 끝 위치를 얻습니다.
l int getSelectionStart(): 선택된 텍스트의 시작 위치를 얻습니다.
l String getText(): 현재의 텍스트를 얻습니다.
l boolean isEditable(): 편집 가능한 상태인지를 얻습니다.
l void select(int selectionStart, int selectionEnd): 시작 위치부터 끝 위치까지 선택합니다.
l void selectAll(): 모든 텍스트를 선택합니다.
l void setCaretPosition(int position): 삽입 위치(캐럿)를 설정합니다.
l void setEditable(boolean b): 편집 상태를 설정합니다.
l void setSelectionEnd(int selectionEnd): 선택 영역의 끝 위치를 설정합니다.
l void setSelectionStart(int selectionStart): 선택 영역의 시작 위치를 설정합니다.
l void setText(String t): 현재 텍스트를 설정합니다.
다. 텍스트 필드(TextField) 컴포넌트
텍스트 필드 컴포넌트의 기능을 제공해 주기 위한 TextField 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l TextField(): 텍스트 필드를 생성합니다.
l TextField(int columns): 주어진 열의 크기(개수)를 갖는 텍스트 필드를 생성합니다.
l TextField(String text): 주어진 텍스트를 갖는 텍스트 필드를 생성합니다.
l TextField(String text, int columns): 주어진 텍스트와 열의 크기(개수)를 갖는 텍스트 필드를 생성합니다.
l boolean echoCharIsSet(): 에코우 문자가 설정되어 있는지 여부를 얻습니다. 패스워드를 입력받기 위해 일반적으로 텍스트 필드 컴포넌트를 이용합니다. 이 때, 패스워드 대신 화면상에 나타날 문자를 에코우 문자라 합니다.
l int getColumns(): 열의 크기(개수)를 얻습니다.
l char getEchoChar(): 에코우 문자를 얻습니다.
l void setColumns(int columns): 텍스트 필드의 크기인 열의 크기(개수)를 설정합니다.
l void setEchoChar(char c): 에코우 문자를 설정합니다.
l void setEchoCharacter(char c): setEchoChar(char) 메소드로 바뀌었습니다.
l void setText(String t): 텍스트를 설정합니다.
라. 텍스트 영역(TextArea) 컴포넌트
텍스트 영역 컴포넌트의 기능을 제공해 주기 위한 TextArea 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l static int SCROLLBARS_BOTH: 수평과 수직 스크롤바 모두를 생성하고 디스플레이 합니다.
l static int SCROLLBARS_HORIZONTAL_ONLY: 수평 스크롤바 만을 생성하고 디스플레이 합니다.
l static int SCROLLBARS_VERTICAL_ONLY: 수직 스크롤바 만을 생성하고 디스플레이 합니다.
l static int SCROLLBARS_NONE: 스크롤바를 생성하지 않습니다.
l TextArea(): 텍스트 영역(TextArea)을 생성합니다.
l TextArea(int rows, int columns): 주어진 행과 열을 갖는 텍스트 영역을 생성합니다.
l TextArea(String text): 주어진 텍스트를 갖는 텍스트 영역을 생성합니다.
l TextArea(String text, int rows, int columns): 주어진 행, 열, 텍스트를 갖는 텍스트 영역을 생성합니다.
l TextArea(String text, int rows, int columns, int scrollbars): 주어진 행, 열, 텍스트, 그리고 스크롤바를 갖는 텍스트 영역을 생성합니다.
l void append(String str): 문자열을 텍스트 영역에 추가합니다.
l void appendText(String str): append(String) 메소드로 바뀌었습니다.
l int getColumns(): 열의 크기(개수)를 얻습니다.
l int getRows(): 행의 크기(개수)를 얻습니다.
l void insert(String str, int pos): 주어진 위치(라인)에 문자열을 삽입합니다.
l void insertText(String str, int pos): insert(String, int) 메소드로 바뀌었습니다.
l void replaceRange(String str, int start, int end): 시작 위치부터 끝 위치 사이의 문자열을 주어진 문자열로 대체합니다.
l void replaceText(String str, int start, int end): replaceRange(String, int, int) 메소드로 바뀌었습니다.
l void setColumns(int columns): 열의 크기(개수)를 설정합니다.
l void setRows(int rows): 행의 크기(개수)를 설정합니다.
4. 컨테이너와 레이아웃 관리자(Layout Manager)
가. 컨테이너 내에서의 컴포넌트의 레이아웃
모든 컨테이너는 기본적으로 디폴트 레이아웃 관리자를 가지고 있고, 이러한 레이아웃 관리자는 LayoutManage 인터페이스를 구현하고 있습니다. 만약, 컨테이너의 디폴트 레이아웃 관리자가 만족스럽지못하더라고, 컨테이너의 레이아웃 관리자를 쉽게 다른 레이아웃 관리자로 바꿀 수 있습니다. AWT가 제공해 주는 레이아웃 관리자들에 대해 다음과 같은 몇 가지로 분류할 수 있습니다.
l 매우 간단한(very simple) 레이아웃 관리자: 플로우 레이아웃(FlowLayout), 그리드 레이아웃(GridLayout)
l 특수 목적(special purpose) 레이아웃 관리자: 보더 레이아웃(BorderLayout), 카드 레이아웃(CardLayout)
l 매우 유용한(ultra-flexible) 레이아웃 관리자: 그리드백 레이아웃(GridBagLayout)
나. 플로우 레이아웃 관리자(FlowLayout)
플로우 레이아웃 관리자는 패널 컴포넌트를 위한 디폴트 레이아웃 관리자입니다. 플로우 레이아웃 관리자는 컴포넌트를 레이아웃 할 때, 왼쪽에서 오른쪽으로 그리고 위에서 아래로 차례대로 레이아웃합니다. 이러한 레이아웃은 텍스트 편집기를 이용하여 텍스트를 입력하는 것과 같이 생각하면 쉽습니다. 다시 말해서, 텍스트 편집기를 이용하여 글자를 입력할 때, 왼쪽에서 오른쪽으로 차례대로 입력하게 되고, 한 줄이 다 차면 다음 줄로 넘어가지요. 이와 마찬가지로, 플로우 레이아웃 관리자도 컴포넌트를 컨테이너의 왼쪽에서 오른쪽으로 하나씩 채워가다가, 오른쪽 끝에 다다르면 다음 줄로 넘어가게됩니다. 지금까지 AWT 컴포넌트를 살펴볼 때, 알게 모르게 많이 사용했던 레이아웃 관리자입니다. 다음에 나오는 자바 프로그램은 플로우 레이아웃 관리자의 사용을 보여주는 간단한 프로그램입니다.
import java.io.*; import java.awt.*; class FlowLayoutTest extends Frame { public FlowLayoutTest() { Panel p = new Panel(); p.add(new Button("Button 1")); p.add(new Button("Button 2")); p.add(new Button("Button 3")); p.add(new Button("Button 4")); p.add(new Button("Button"), "Button"); Choice colorChooser = new Choice(); colorChooser.add("Green"); colorChooser.add("Red"); colorChooser.add("Blue"); p.add(colorChooser, "Colors"); add(p); } public static void main(String args[]) { FlowLayoutTest f = new FlowLayoutTest(); f.pack(); f.setTitle("FlowLayout"); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java FlowLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 15. FlowLayoutTest.java>
FlowLayout 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l static int LEFT: 플로우 레이아웃 관리자의 왼쪽 정렬 값을 나타냅니다.
l static int CENTER: 플로우 레이아웃 관리자의 가운데 정렬 값을 나타냅니다.
l static int RIGHT: 플로우 레이아웃 관리자의 오른쪽 정렬 값을 나타냅니다.
l static int LEADING: 플로우 레이아웃 관리자의 리딩 에지(leading edge) 정렬 값을 나타냅니다.
l static int TRAILING: 플로우 레이아웃 관리자의 드레일링 에지(leading edge) 정렬 값을 나타냅니다.
l FlowLayout(): 디폴트로 가운데 정렬을 하고, 수평과 수직 간격이 5인 플로우 레이아웃 관리자를 생성합니다.
l FlowLayout(int align): 주어진 정렬을 하고, 수평과 수직 간격이 5인 플로우 레이아웃 관리자를 생성합니다.
l FlowLayout(int align, int hgap, int vgap): 주어진 정렬을 하고, 수평과 수직 간격이 각각 hgap과 vgap인 플로우 레이아웃 관리자를 생성합니다.
l void addLayoutComponent(String name, Component comp): 주어진 이름으로 컴포넌트를 추가합니다.
l void removeLayoutComponent(Component comp): 컴포넌트를 제거합니다.
l int getAlignment(): 정렬 방식의 값을 얻습니다.
l void setAlignment(int align): 정렬 방식을 설정합니다.
l void layoutContainer(Container target): 컨테이너에 대한 레이아웃을 행합니다.
l int getHgap(): 수평 간격을 얻습니다.
l int getVgap(): 수직 간격을 얻습니다.
l void setHgap(int hgap): 수평 간격을 설정합니다.
l void setVgap(int vgap): 수직 간격을 설정합니다.
다. 그리드 레이아웃 관리자(GridLayout)
그리드 레이아웃 관리자는 컨테이너의 영역을 주어진 행과 열 크기의 셀들로 나누고, 동등한 크기의 각 셀에 컴포넌트를 하나씩 위치시키므로, 모든 컴포넌트의 크기는 동일하게 됩니다. 그리드 레이아웃관리자는 셀 단위의 레이아웃을 수행하고, 이러한 셀을 사각형 그리드(rectangular grid)라 할 수 있으므로, 그리드 레이아웃 관리자라 하는 것입니다.
다음에 나오는 자바 프로그램은 플로우 레이아웃 관리자의 사용을 보여주는 간단한 프로그램입니다.
import java.io.*; import java.awt.*; class GridLayoutTest extends Frame { public GridLayoutTest() { Panel p1 = new Panel(new GridLayout()); p1.add(new Button("Button 1")); p1.add(new Button("Button 2")); p1.add(new Button("Button 3")); p1.add(new Button("Button 4")); p1.add(new Button("Button"), "Button"); Choice colorChooser = new Choice(); colorChooser.add("Green"); colorChooser.add("Red"); colorChooser.add("Blue"); p1.add(colorChooser, "Colors"); Panel p2 = new Panel(new GridLayout(2, 3)); p2.add(new Button("Button 1")); p2.add(new Button("Button 2")); p2.add(new Button("Button 3")); p2.add(new Button("Button 4")); p2.add(new Button("Button"), "Button"); add("North", p1); add("Center", p2); } public static void main(String args[]) { GridLayoutTest f = new GridLayoutTest(); f.pack(); f.setTitle("GridLayout"); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java GridLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 16. GridLayoutTest.java>
위의 예제에서는 그리드 레이아웃 관리자를 사용하는 두 개의 패널 컴포넌트를 프레임이 포함하도록 하고 있습니다. 이 때, 프레임의 레이아웃 관리자는 윈도우 컴포넌트의 디폴트 레이아웃 관리자인 보더 레이아웃 관리자입니다. 그리고, 첫 번째 패널 컴포넌트는 하나의 행을 갖는 그리드 레이아웃 관리자를 갖고, 두 번째 패널 컴포넌트는 2행 3열을 갖고 수평 간격은 10, 수직 간격은 5인 그리드 레이아웃관리자를 갖고 있습니다.
GridLayout 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l GridLayout(): 단 하나의 행을 갖고 각 컴포넌트는 하나의 열을 차지하도록 레이아웃하는 그리드 레이아웃 관리자를 생성합니다.
l GridLayout(int rows, int cols): 주어진 행과 열을 갖는 레이아웃하는 그리드 레이아웃 관리자를 생성합니다.
l GridLayout(int rows, int cols, int hgap, int vgap): 주어진 행과 열을 갖고 수평과 수직 간격이 각각 hgap과 vgap인 그리드 레이아웃 관리자를 생성합니다.
l void addLayoutComponent(String name, Component comp): 주어진 이름으로 컴포넌트를 추가합니다.
l int getColumns(): 열의 크기를 얻습니다.
l int getHgap(): 수평 간격을 얻습니다.
l int getRows(): 행의 크기를 얻습니다.
l int getVgap(): 수직 간격을 얻습니다.
l void layoutContainer(Container parent): 컨테이너를 레이아웃 합니다.
l void removeLayoutComponent(Component comp): 주어진 컴포넌트를 제거합니다.
l void setColumns(int cols): 열의 크기를 설정합니다.
l void setHgap(int hgap): 수평 간격을 설정합니다.
l void setRows(int rows): 행의 크기를 설정합니다.
l void setVgap(int vgap): 수직 간격을 설정합니다.
라. 보더 레이아웃 관리자(BorderLayout )
보더 레이아웃 관리자는 프레임(Frame) 컴포넌트와 대화상자(Dialog) 컴포넌트 등과 같은 모든 윈도우(Window) 컴포넌트를 위한 디폴트 레이아웃 관리자입니다. 보더 레이아웃은 동(east), 서(west), 남(south),북(north), 그리고 중앙(center) 등 다섯 개의 영역으로 나누어 컴포넌트들을 관리합니다. 이 다섯 개의 영역은 기본적으로 중앙 영역에 위치시키고, 사용자가 나머지 영역(동, 서, 남, 북) 중 한 영역에 위치시키고자 하면 해당 영역을 할당하고, 나머지 부분은 다시 중앙 영역에 할당하게 됩니다. 다음에 나오는 자바 프로그램은 보더 레이아웃 관리자를 사용하는 예를 보여주고 있습니다.
import java.awt.*; class BorderLayoutTest extends Frame { public BorderLayoutTest() { Window w1 = new Window(this); w1.setLayout(new BorderLayout(10, 5)); w1.add("East", new Button("W1-East")); w1.add("West", new Button("W1-West")); w1.add("North", new Button("W1-North")); w1.add("Center", new Button("W1-Center")); w1.add("South", new Button("W1-South")); w1.setLocation(100,100); w1.setSize(200,100); w1.show(); Window w2 = new Window(this); w2.add("East", new Button("W2-East")); w2.add("West", new Button("W2-West")); w2.add("North", new Button("W2-North")); w2.add("South", new Button("W2-South")); w2.setLocation(310,100); w2.setSize(200,100); w2.show(); Window w3 = new Window(this); w3.add("Center", new Button("W3-Center")); w3.setLocation(100,210); w3.setSize(200,100); w3.show(); Window w4 = new Window(this); BorderLayout b = new BorderLayout(8, 16); w4.setLayout(b); w4.add("East", new Button("W4-East")); w4.add("West", new Button("W4-West")); w4.add(new Button("W4-Center")); w4.setLocation(310,210); w4.setSize(200,100); w4.show(); } public static void main(String args[]) { BorderLayoutTest f = new BorderLayoutTest(); f.pack(); f.setTitle("BorderLayout"); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java BorderLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 17. BorderLayoutTest.java>
BorderLayout 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l BorderLayout(): 컴포넌트들 간의 수평 간격과 수직 간격이 0인 보더 레이아웃 관리자를 생성합니다.
l BorderLayout(int hgap, int vgap): 컴포넌트들 간의 수평 간격(hgap)과 수직 간격(vgap)을 갖는 보더 레이아웃 관리자를 생성합니다.
l int getHgap(): 컴포넌트들 간의 수평 간격(hgap)을 얻습니다.
l int getVgap(): 컴포넌트들 간의 수직 간격(vgap)을 얻습니다.
l void setHgap(int hgap): 컴포넌트들 간의 수평 간격(hgap)을 설정합니다.
l void setVgap(int vgap):: 컴포넌트들 간의 수직 간격(vgap)을 설정합니다.
마. 카드 레이아웃 관리자(CardLayout)
카드 레이아웃 관리자는 여러 장의 카드를 겹쳐 배치하는 식으로 관리하고, 컨테이너가 포함하고 있는 컴포넌트들을 한 장의 카드처럼 다루어. 한 번에 한 장씩 사용자가 보기를 원하는 카드를 보여주고,여러 컴포넌트가 카드 레이아웃 관리자에 등록이 될 경우 가장 처음 등록된 컴포넌트를 디폴트로 보여줍니다.
이러한 레이아웃은 일반적으로 사용자 옵션을 입력받기 위해 윈도우에서 많이 사용하는 하는 레이아웃입니다. 옵션 메뉴를 분류하여 여러 장(카드로 비유됨)을 준비하여 두고, 사용자가 보기를 원하는 카드(윈도우에서는 탭이라 함)를 보여주기 위해 카드 레이아웃 관리자를 사용합니다. 이 때 각 장의 메뉴는 하나의 패널을 이용하여 관리하는 것이 효율적입니다. 다음에 나오는 자바 프로그램은 카드 레이아웃 관리자의 사용을 보여주는 간단한 프로그램입니다.
import java.io.*; import java.awt.*; class CardLayoutTest extends Frame { CardLayout c=null; public CardLayoutTest() { c = new CardLayout(); setLayout(c); Panel p1 = new Panel(); p1.setLayout(new BorderLayout()); p1.add("East", new Button("East")); p1.add("West", new Button("West")); p1.add("North", new Button("North")); p1.add("Center", new Button("Center")); p1.add("South", new Button("South")); Panel p2 = new Panel(); p2.add(new Button("Button 1")); p2.add(new Button("Button 2")); p2.add(new Button("Button 3")); p2.add(new Button("Button 4")); Panel p3 = new Panel(); p3.setLayout(new GridLayout(4, 1)); p3.add(new Button("Button p3-1")); p3.add(new Button("Button p3-2")); p3.add(new Button("Button p3-3")); p3.add(new Button("Button p3-4")); add(p1, "BorderLayout"); add(p2, "DefaultLayout"); add(p3, "GridLayout"); add(new Button("Button"), "Button"); Choice colorChooser = new Choice(); colorChooser.add("Green"); colorChooser.add("Red"); colorChooser.add("Blue"); add(colorChooser, "Colors"); } public static void main(String args[]) { CardLayoutTest f = new CardLayoutTest(); int ch; f.pack(); f.setTitle("CardLayout"); f.setVisible(true); try { while((ch=System.in.read()) != -1) { if(f.c != null) { f.c.next(f); } } } catch(IOException e) { } } } /* * Results: D:\AIIT\JAVA\Working\08>java CardLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 18. CardLayoutTest.java>
위의 자바 프로그램에서는 다섯 개의 컴포넌트를 프레임에 추가하여, 이를 카드 레이아웃 관리자를 이용하여 관리하고 있습니다. 이 때, 다섯 장의 카드를 가지고 있다고 볼 수 있습니다. 그리고, 위의 프로그램에서는 아직 이벤트 처리에 대해서 살펴보지 않았기 때문에 간단하게 리턴키를 치면 다음 카드로 바꾸도록 하고 있는데, MS 플랫폼에서는 리턴키가 '\n'와 '\r' 등 두 문자로 구성되기 때문에 두 개의 키가 쳐진 것처럼 카드가 두 장씩 넘어가데 됩니다. 그렇기 때문에 위와 같이 리턴키를 입력받아 카드 레이아웃 관리자를 테스트하고자 한다면, 카드는 두 장씩 넘어가기 때문에 홀수 장을 만들어야 합니다.
CardLayout 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l CardLayout(): 컴포넌트들 간의 수평 간격과 수직 간격이 0인 카드 레이아웃 관리자를 생성합니다.
l CardLayout(int hgap, int vgap): 컴포넌트들 간의 수평 간격이 hgap이고, 수직 간격이 vgap인 카드 레이아웃 관리자를 생성합니다.
l void addLayoutComponent(Component comp, Object constraints): 주어진 컴포넌트를 카드 레이아웃 관리자의 내부 이름 테이블에 삽입합니다.
l void addLayoutComponent(String name, Component comp): addLayoutComponent(Component, Object) 메소드로 바뀌었습니다.
l void first(Container parent): 주어진 컨테이너에 포함된 첫 번째 카드를 보여줍니다.
l void last(Container parent): 주어진 컨테이너에 포함된 마지막 번째 카드를 보여줍니다.
l void next(Container parent): 주어진 컨테이너에 포함된 다음 카드를 보여줍니다.
l void previous(Container parent): 주어진 컨테이너에 포함된 이전 카드를 보여줍니다.
l void show(Container parent, String name): 주어진 컨테이너에 포함된 컴포넌트 중 주어진 이름을 가진 컴포넌트로 전환합니다(보여줍니다).
l void removeLayoutComponent(Component comp): 주어진 컴포넌트를 제거합니다.
l void layoutContainer(Container parent): 이 카드 레이아웃 관리자를 이용하여 주어진 컨테이너에 포함된 컴포넌트들을 레이아웃 합니다.
l int getHgap(): 컴포넌트들 간의 수평 간격(hgap)을 얻습니다.
l int getVgap(): 컴포넌트들 간의 수직 간격(vgap)을 얻습니다.
l void setHgap(int hgap): 컴포넌트들 간의 수평 간격(hgap)을 설정합니다.
l void setVgap(int vgap):: 컴포넌트들 간의 수직 간격(vgap)을 설정합니다.
바. 그리드백 레이아웃 관리자(GridBagLayout)
그리드백 레이아웃 관리자는 AWT에서 제공해 주는 레이아웃 관리자 중에서 가장 복잡하고 다양한 형태를 가질 수 있는 레이아웃 관리자입니다. 그리드백 레이아웃 관리자는 HTML 페이지를 생성하기위해 사용하는 테이블과 같은 방식으로 레이아웃을 수행합니다. 다시 말해서, 레이아웃 영역을 기본적으로 셀 단위로 나누어 놓고, 행과 열에 대해 셀 크기를 확장할 수 있도록 하는 것입니다. 그리드 레이아웃 관리자는 모든 컴포넌트가 같은 크기의 셀에 위치되고 크기 변경이 불가능하지만, 그리드백 레이아웃 관리자는 셀 단위의 레이아웃을 행하기는 하지만 각 컴포넌트가 서로 다른 크기를 가질 수 있도록 할 수 있습니다.
다음에 나오는 자바 프로그램은 그리드백 레이아웃 관리자의 사용을 보여주는 간단한 프로그램입니다.
import java.awt.*; public class GridBagLayoutTest extends Frame { TextField smtpServer, mailFrom, rcptTo, subject; TextArea body; GridBagLayout gbl; GridBagConstraints gbc; public GridBagLayoutTest() { smtpServer = new TextField(40); mailFrom = new TextField(40); rcptTo = new TextField(40); subject = new TextField(40); body = new TextArea(5, 40); gbl = new GridBagLayout(); gbc = new GridBagConstraints(); setLayout(gbl); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; add(new Label("메일서버: ", Label.RIGHT), 0, 0, 1, 1); add(smtpServer, 1, 0, 3, 1); add(new Label("From: ", Label.RIGHT), 0, 1, 1, 1); add( mailFrom, 1, 1, 3, 1); add(new Label("To: ", Label.RIGHT), 0, 2, 1, 1); add(rcptTo, 1, 2, 3, 1); add(new Label("제 목: ", Label.RIGHT), 0, 3, 1, 1); add(subject, 1, 3, 3, 1); add(new Label("내 용: ", Label.RIGHT), 0, 4, 1, 1); add(body, 1, 4, 1, 1); add(new Button("Send"), 0, 5, 2, 1); pack(); // setSize(400, 300); } private void add(Component c, int x, int y, int w, int h) { gbc.gridx = x; gbc.gridy = y; gbc.gridwidth = w; gbc.gridheight = h; gbl.setConstraints(c, gbc); add(c); } public static void main(String args[]) { GridBagLayoutTest f = new GridBagLayoutTest(); f.setTitle("GridBagLayout"); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java GridBagLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 19. GridBagLayoutTest.java>
그리드백 레이아웃 관리자가 컴포넌트들에 대한 레이아웃을 행할 때, 각 컴포넌트가 차지하는 셀의 위치, 수평 크기, 수직 크기 등을 설정해 주어야 하는데, 이를 위해 자바에서는 GridBagConstraints 클래스를 제공해 줍니다. 먼저, GridBagConstraints 클래스가 제공해주는 기능을 살펴보도록 하겠습니다.
l GridBagConstraints.gridx, GridBagConstraints.gridy: 컴포넌트가 위치할 셀의 x 값과 y 값을 나타내며, 가장 왼쪽 위 셀의 gridx과 gridy 값은 0입니다. 컴포넌트를 순서대로 위치시키고자 할 때는GridBagConstraints.RELATIVE를 사용합니다.
l GridBagConstraints.gridwidth, GridBagConstraints.gridheight: 컴포넌트가 차지할 너비와 높이를 나타내는 셀의 개수이며, 디폴트 값은 1입니다. gridwidth를 GridBagConstraints.REMAINDER 값으로 설정하면현재 행의 마지막 셀이되고, gridheight 를 GridBagConstraints.REMAINDER 값으로 설정하면 현재 열의 마지막 셀이됩니다. gridwidth를 GridBagConstraints. RELATIVE 값으로 설정하면 현재 행의 다음 셀부터 마지막 셀까지 차지하고, gridheight 를 GridBagConstraints. RELATIVE 값으로 설정하면 현재 열의 다음 셀부터 마지막 셀까지 차지하도록 합니다.
l GridBagConstraints.fill: 컴포넌트의 디스플레이 영역이 컴포넌트가 요청한 크기보다 클 때, 크기설정을 다시 할 것인가를 결정합니다. GridBagConstraints 클래스는 다음과 같은 값을 가능한 값으로 제공해 주고 있습니다.
l GridBagConstraints.NONE: 디폴트 값
l GridBagConstraints.HORIZONTAL: 수평적으로 확장하고 수직적으로는 확장하지 않습니다.
l GridBagConstraints. VERTICAL: 수직적으로 확장하고 수평적으로는 확장하지 않습니다.
l GridBagConstraints.BOTH: 수평 및 수직으로 확장합니다.
l GridBagConstraints.ipadx, GridBagConstraints.ipady: 컴포넌트 너비의 최소값에 (ipadx * 2) 픽셀을 더하고, 컴포넌트 높이의 최소값에 (ipady * 2) 픽셀을 더합니다.
l GridBagConstraints.insets: 컴포넌트와 디스플레이 영역의 엣지 사이의 공간의 크기를 나타내고, 다음과 같은 값을 GridBagConstraints 클래스에서 제공해 줍니다.
l GridBagConstraints.anchor: 컴포넌트가 디스플레이 영역보다 작을 때, 컴포넌트가 위치할 위치를 나타냅니다. 이 값으로는 GridBagConstraints.CENTER(디폴트 값), GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST, GridBagConstraints.EAST, GridBagConstraints.SOUTHEAST, GridBagConstraints.SOUTH, GridBagConstraints.SOUTHWEST, GridBagConstraints.WEST, and GridBagConstraints.NORTHWEST. 등이 있습니다.
l GridBagConstraints.weightx, GridBagConstraints.weighty: 컴포넌트의 디스플레이 영역이 컴포넌트가 요청한 크기보다 클 때 남는 영역을 각 컴포넌트들에게 배분해 주어야 하는데, 이 때 컴포넌트가 차지할 너비(weightx)와 높이(weighty)에 대한 웨이트(weight)를 나타냅니다. 이 너비와 높이에 대한 웨이트는 각 컴포넌트마다 달리 줄 수 있습니다. 만약, 모든 컴포넌트의 너비와 높이에 대한 웨이트가 0이면, 디스플레이 영역이 커지더라도(사용자가 윈도우의 창을 키울 때) 각 컴포넌트에 배당되는 영역이 없으므로 모든 컴포넌트들은 한군데 위치하게 되고 남는 영역은 그냥 빈공간으로 나타나게 됩니다.
다음에 나오는 자바 프로그램은 GridBagConstraints 객체의 값을 적당하게 설정하여 각 컴포넌트를 컨테이너에 등록한 후, 그리드백 레이아웃 관리자를 이용하여 보여주는 프로그램입니다.
import java.awt.*; class GridBagLayoutTest2 extends Frame { public GridBagLayoutTest2() { GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); setLayout(gridbag); c.ipadx = 8; c.ipadx = 8; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.weighty = 1.0; makebutton("Button1", gridbag, c); makebutton("Button2", gridbag, c); makebutton("Button3", gridbag, c); c.gridwidth = GridBagConstraints.REMAINDER; //end row c.weightx = 0.5; c.weighty = 0.5; makebutton("Button4", gridbag, c); c.fill = GridBagConstraints.BOTH; c.weightx = 0.0; c.weighty = 0.0; //reset to the default makebutton("Button5", gridbag, c); //another row c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row makebutton("Button6", gridbag, c); c.gridwidth = GridBagConstraints.REMAINDER; //end row c.weightx = 0.75; c.weighty = 0.75; makebutton("Button7", gridbag, c); c.gridwidth = 1; //reset to the default c.gridheight = 2; c.weightx = 0.25; c.weighty = 0.25; makebutton("Button8", gridbag, c); c.weighty = 0.0; //reset to the default c.gridwidth = GridBagConstraints.REMAINDER; //end row c.gridheight = 1; //reset to the default makebutton("Button9", gridbag, c); makebutton("Button10", gridbag, c); setSize(300, 100); } protected void makebutton(String name, GridBagLayout gridbag, GridBagConstraints c) { Button button = new Button(name); gridbag.setConstraints(button, c); add(button); } public static void main(String args[]) { GridBagLayoutTest2 f = new GridBagLayoutTest2(); f.pack(); f.setTitle("GridBagLayout2"); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java GridBagLayoutTest2 D:\AIIT\JAVA\Working\08> */ |
<프로그램 20. GridBagLayoutTest2.java>
위의 자바 프로그램을 실행한 후, 윈도우의 크기를 적당하게 조절해 보면, 주어진 웨이트에 따라 남는 영역이 배분되므로 각 컴포넌트의 크기가 웨이트에 따라 변하게 됨을 알 수 있습니다. 그리고, GridBagConstraints.REMAINDER와 GridBagConstraints. RELATIVE의 차이점도 볼 수 있습니다.
GridBagLayout 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l GridBagLayout(): 그리드백 레이아웃 관리자를 생성합니다.
l void addLayoutComponent(Component comp, Object constraints): 주어진 컴포넌트를 주어진 constraints 객체를 이용하여 추가합니다.
l void addLayoutComponent(String name, Component comp): 주어진 이름으로 컴포넌트를 추가합니다.
l GridBagConstraints getConstraints(Component comp): 주어진 컴포넌트에 연결된 GridBagConstraints 객체를 얻습니다.
l Point getLayoutOrigin(): 레이아웃 그리드의 시작 위치값을 얻스비다.
l double[][] getLayoutWeights(): 레이아웃 그리드의 행과 열이 갖는 웨이트 배열을 얻습니다.
l void invalidateLayout(Container target): 레이아웃을 무효화(invalidate) 합니다.
l void layoutContainer(Container parent): 이 그리드백 레이아웃 관리자를 이용하여 주어진 컨테이너를 레이아웃 합니다.
l void removeLayoutComponent(Component comp): 주어진 컴포넌트를 제거합니다.
l void setConstraints(Component comp, GridBagConstraints constraints): 주어진 컴포넌트를 위한 constraints를 설정합니다.
사. 레이아웃 관리자를 사용하지 않는 레이아웃(Absolute Positioning)
지금까지 여러 가지 형태의 레이아웃 관리자에 대하여 살펴보았습니다. 이러한 레이아웃 관리자는 시스템(플랫폼)에 독립적으로 컴포넌트들을 컨테이너에 레이아웃 할 수 있도록 해 주었습니다. 여기에서는 사용자가 원하는 위치에 직접 컴포넌트를 위치하도록 하는 방법에 대하여 살펴보도록 하겠습니다. 이러한 방법은 GUI 툴을 이용하여 컴포넌트들에 대한 레이아웃을 행할 때 사용될 수 있는 방법입니다. 그러나, 이러한 방법은 시스템의 폰트가 바뀐다거나 자바 프로그램을 실행하는 플랫폼이 바뀐다거나 할 때, 컴포넌트의 레이아웃이 처음에 의도한 것과는 다르게 나타날 수 있으므로 주의하여야 합니다.
다음에 나오는 자바 프로그램은 레이아웃 관리자를 사용하지 않고, 컴포넌트의 위치를 직접 설정해 주는 방법을 보여주는 프로그램입니다.
import java.awt.*; public class NoLayoutTest extends Frame { Button b1, b2, b3; public NoLayoutTest() { Insets insets; setLayout(null); setSize(200, 100); // setVisible(true); // (a) b1 = new Button("one"); b2 = new Button("two"); b3 = new Button("three"); insets = getInsets(); b1.setBounds(50 + insets.left, 5 + insets.top, 50, 20); b2.setLocation(new Point(70 + insets.left, 35 + insets.top)); b2.setSize(new Dimension(50, 20)); b3.setLocation(130 + insets.left, 15 + insets.top); b3.setSize(50, 30); add(b1); add(b2); add(b3); } public static void main(String args[]) { NoLayoutTest f = new NoLayoutTest(); f.setTitle("NoLayout"); f.setVisible(true); // (b) } } /* * Results: (a) 부분을 주석처리한 후 실행 D:\AIIT\JAVA\Working\08>java NoLayoutTest (b) 부분을 주석처리한 후 실행 D:\AIIT\JAVA\Working\08>java NoLayoutTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 21. NoLayoutTest.java>
위의 자바 프로그램을 살펴보면, 레이아웃 관리자를 사용하지 않고, 자바 프로그램 개발자가 임의대로 레이아웃을 하려 할 때 주의해야 할 점 중 하나를 보여주고 있습니다. 자바에서 테두리를 구하기 위해서는 먼저 컴포넌트가 보이는(visible) 상태여야 합니다. 그렇지 않을 경우, 테두리(inset)의 값은 모두 0이 됩니다. 그러한 이유로, 위와 같은 결과가 발생하는 것입니다.
레이아웃 관리자를 사용하지 않고 컴포넌트의 위치를 직접 설정할 수 있도록 하기 위해, Component 클래스가 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l void setLocation(int x, int y): 컴포넌트를 새로운 위치로 옮깁니다.
l void setLocation(Point p): 컴포넌트를 새로운 위치로 옮깁니다.
l Dimension size(): getSize() 메소드로 바뀌었습니다.
l void setSize(Dimension d): 컴포넌트의 너비와 높이를 각각 d.width와 d.height로 설정합니다.
l void setSize(int width, int height): 컴포넌트의 너비와 높이를 각각 width와 height로 설정합니다.
l void reshape(int x, int y, int width, int height): setBounds(int, int, int, int) 메소드로 바뀌었습니다.
l void resize(Dimension d): setSize(Dimension) 메소드로 바뀌었습니다.
l void resize(int width, int height): setSize(int, int) 메소드로 바뀌었습니다.
l void setBounds(int x, int y, int width, int height): 컴포넌트를 주어진 위치로 옮기고 크기를 변경합니다.
l void setBounds(Rectangle r): 컴포넌트를 주어진 위치로 옮기고 크기를 변경합니다.
5. 메뉴(Menu)
가. 메뉴
자바 애플릿과 애플리케이션에서 원하는 형태의 메뉴를 사용할 수 있도록 해 줍니다. 윈도우는 몇 개의 메뉴를 갖고, 각 메뉴는 다시 하나 또는 그 이상의 메뉴, 메뉴 아이템, 메뉴 분리자 등을 갖게 할 수 있습니다. 이 때, 메뉴는 항상 메뉴바 내에서만 사용될 수 있고, 메뉴바는 윈도우(또는 프레임)에만 연결될 수 있습니다.
AWT에서 메뉴는 몇 개의 클래스에 의해서 제공되고 있고, 이러한 클래스들은 Component 클래스를 상속하지 않고 있는데, 이는 대부분의 플랫폼들이 메뉴의 기능을 상당히 제한하고 있기 때문입니다. 이러한 이유로, 메뉴 클래스들은 MenuComponent 클래스를 상속하고 있습니다. AWT에서 제공해 주고 있는 메뉴 클래스들의 클래스 계층도를 살펴보면 다음과 같습니다.
<그림 4. 메뉴 컴포넌트 계층도>
메뉴를 제공해 주기 위한 각 클래스들에 대해 살펴보면 다음과 같습니다.
l MenuComponent 클래스: MenuComponent 클래스는 자바에서 메뉴를 제공하기 위한 기본적인 기능들을 정의하고 있는 클래스이며, 다른 메뉴 관련 클래스들은 이 클래스를 상속하는 하위클래스입니다.
l MenuBar 클래스: 메뉴바를 표현하기 위한 클래스입니다. 메뉴바는 윈도우에 연결되어야 하고, 패널에 연결되어서는 안됩니다. 왜냐하면, MenuComponent 객체를 포함하기 위해서는 MenuContainer인터페이스를 구현해야 되는데, 현재 AWT 클래스들 중에서는 Frame, Menu, 그리고 MenuBar 클래스들만이 MenuContainer 인터페이스를 구현하고 있기 때문입니다.
l MenuItem 클래스: 메뉴 내에 있는 각 아이템을 표현하기 위한 클래스입니다..
l Menu 클래스: 메뉴를 표현하기 위한 클래스입니다. Menu 클래스는 MenuItem 클래스의 하위클래스로 구현되었기 때문에, 메뉴를 다른 메뉴에 추가하기만 하면 하나의 부메뉴를 생성할 수 있습니다.
l CheckboxMenuItem 클래스: 체크박스를 포함하고 있는 메뉴 아이템으로, MenuItem 클래스의 하위클래스입니다.
다음에 나오는 자바 프로그램은 메뉴를 사용하는 예를 보여주고 있습니다.
import java.awt.*; class MenuTest extends Frame { public MenuTest() { setLayout(new FlowLayout()); MenuBar menuBar; Menu fileMenu, editMenu, viewMenu, zoomMenu, helpMenu; MenuItem undoItem, redoItem, cutItem, copyItem, pasteItem; menuBar = new MenuBar(); setMenuBar(menuBar); fileMenu = new Menu("File", true); menuBar.add(fileMenu); fileMenu.add(new MenuItem("New")); fileMenu.add(new MenuItem("Open")); fileMenu.add(new MenuItem("Close")); fileMenu.addSeparator(); fileMenu.add(new MenuItem("Save")); fileMenu.add(new MenuItem("Save As")); fileMenu.add(new MenuItem("Save All")); editMenu = new Menu("Edit", false); menuBar.add(editMenu); undoItem = new MenuItem("Undo"); editMenu.add(undoItem); redoItem = new MenuItem("Redo"); redoItem.setEnabled(false); editMenu.add(redoItem); editMenu.addSeparator(); cutItem = new MenuItem("Cut"); cutItem.setEnabled(false); editMenu.add(cutItem); copyItem = new MenuItem("Copy"); copyItem.setEnabled(false); editMenu.add(copyItem); pasteItem = new MenuItem("Paste"); pasteItem.setEnabled(false); editMenu.add(pasteItem); zoomMenu = new Menu("Zoom"); zoomMenu.add(new CheckboxMenuItem("4:1")); zoomMenu.add(new CheckboxMenuItem("2:1")); zoomMenu.add(new CheckboxMenuItem("1:1")); zoomMenu.add(new CheckboxMenuItem("1:2")); zoomMenu.add(new CheckboxMenuItem("1:4")); viewMenu = new Menu("View"); menuBar.add(viewMenu); viewMenu.add(zoomMenu); viewMenu.addSeparator(); viewMenu.add(new CheckboxMenuItem("Toolbar")); viewMenu.add(new CheckboxMenuItem("StatusBar")); helpMenu = new Menu("Help"); menuBar.setHelpMenu(helpMenu); helpMenu.add(new MenuItem("Help")); helpMenu.add(new MenuItem("About")); } public static void main(String args[]) { MenuTest f = new MenuTest(); f.setSize(200, 60); // pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java MenuTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 22. MenuTest.java>
나. MenuComponent 클래스
MenuComponent 클래스가 제공해 주는 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l MenuComponent(): MenuComponent 객체를 생성합니다.
l Font getFont(): 메뉴 컴포넌트에 사용된 폰트를 얻습니다.
l String getName(): 메뉴 컴포넌트의 이름을 얻습니다.
l MenuContainer getParent(): 메뉴 컴포넌트를 위한 부모 컨테이너를 얻습니다.
l void setFont(Font f): 메뉴 컴포넌트가 사용할 폰트를 설정합니다.
l void setName(String name): 주어진 문자열로 메뉴 컴포넌트의 이름을 설정합니다.
다. 메뉴바(MenuBar) 컴포넌트
메뉴바 컴포넌트의 기능을 제공해 주기 위한 MenuBar 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l MenuBar(): 메뉴바를 생성합니다.
l Menu add(Menu m): 메뉴바에 주어진 메뉴를 추가합니다.
l int countMenus(): getMenuCount() 메소드로 바뀌었습니다.
l void deleteShortcut(MenuShortcut s): 주어진 메뉴 메뉴단축키를 삭제합니다.
l Menu getHelpMenu(): 메뉴바에 주어진 도움말 메뉴를 얻습니다.
l Menu getMenu(int i): 주어진 번호의 메뉴를 얻습니다.
l int getMenuCount(): 메뉴바에 있는 메뉴의 개수를 얻습니다.
l MenuItem getShortcutMenuItem(MenuShortcut s): 주어진 메뉴단축키에 연결된 메뉴 아이템을 얻습니다.
l void remove(int index): 주어진 인덱스에 해당하는 메뉴를 제거합니다.
l void remove(MenuComponent m): 주어진 메뉴 컴포넌트를 제거합니다.
l void setHelpMenu(Menu m): 도움말 메뉴를 설정합니다.
l Enumeration shortcuts(): 메뉴바에 등록된 메뉴단축키를 얻습니다.
라. 메뉴 아이템(MenuItem) 컴포넌트
메뉴 아이템 컴포넌트의 기능을 제공해 주기 위한 MenuItem 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l MenuItem(): 레이블을 갖지 않고, 연결된 메뉴단축키가 없는 메뉴 아이템을 생성합니다.
l MenuItem(String label): 주어진 레이블을 갖고, 연결된 메뉴단축키가 없는 메뉴 아이템을 생성합니다.
l MenuItem(String label, MenuShortcut s): 주어진 레이블을 갖고, 주어진 메뉴단축키가 연결된 메뉴 아이템을 생성합니다.
l void deleteShortcut(): 연결된 메뉴단축키를 제거합니다.
l void disable(): setEnabled(boolean) 메소드로 바뀌었습니다.
l void enable(): setEnabled(boolean) 메소드로 바뀌었습니다.
l void enable(boolean b): setEnabled(boolean) 메소드로 바뀌었습니다.
l String getLabel(): 메뉴 아이템을 위한 레이블을 얻습니다.
l MenuShortcut getShortcut(): 메뉴 아이템에 연결된 메뉴단축키 객체를 얻습니다.
l boolean isEnabled(): 아이템이 활성화되어 있는지를 얻습니다.
l void setEnabled(boolean b): 메뉴 아이템을 활성화 또는 비활성화 되도록 설정합니다.
l void setLabel(String label): 메뉴 아이템을 위한 레이블을 설정합니다.
l void setShortcut(MenuShortcut s): 메뉴 아이템을 위한 메뉴단축키 객체를 설정합니다.
마. 체크박스 메뉴 아이템(CheckboxMenuItem) 컴포넌트
체크박스 메뉴 아이템 컴포넌트의 기능을 제공해 주기 위한 CheckboxMenuItem 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l CheckboxMenuItem(): 레이블이 없는 체크박스 메뉴 아이템을 생성합니다.
l CheckboxMenuItem(String label): 주어진 레이블을 갖는 체크박스 메뉴 아이템을 생성합니다.
l CheckboxMenuItem(String label, boolean state): 주어진 레이블과 선택 상태를 갖는 체크박스 메뉴 아이템을 생성합니다.
l boolean getState(): 체크박스 메뉴 아이템의 선택 상태를 얻습니다.
l void setState(boolean b): 체크박스 메뉴 아이템의 상태를 주어진 상태로 설정합니다.
바. 메뉴(Menu) 컴포넌트
메뉴 객체는 메뉴바에서 디스플레이 되는 풀-다운(pull-down) 메뉴 컴포넌트입니다. 메뉴는 선택적으르로 tear-off 메뉴일 수 있습니다. tear-off 메뉴란 상위 메뉴바(parent menu bar) 또는 상위 메뉴에서 열리고드래그(dreagged) 될 수 있습니다. 그리고 마우스 버튼이 놓인 후에도 스크린 상에 계속 남아 있는 메뉴입니다. 이 tear-off 메뉴는 자바가 운영되는 플랫폼에서 제공해 주어야 하면, 만약 제공되지 않는다면자바의 메뉴 컴포넌트에서도 무시됩니다.
메뉴 컴포넌트의 기능을 제공해 주기 위한 Menu 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l Menu (): 레이블을 갖지 않는 메뉴를 생성합니다.
l Menu(String label): 주어진 레이블을 갖는 메뉴를 생성합니다.
l Menu(String label, boolean tearOff): 주어진 레이블을 갖고, 메뉴가 tear-off 될 수 있는지 여부를 설정하여 메뉴를 생성합니다.
l MenuItem add(MenuItem mi): 메뉴 아이템을 추가합니다.
l void add(String label): 주어진 이름의 메뉴 아이템을 추가합니다.
l void addSeparator(): 메뉴 분리자를 추가합니다.
l int countItems(): getItemCount() 메소드로 바뀌었습니다.
l MenuItem getItem(int index): 주어진 인덱스에 해당하는 메뉴 아이템을 얻습니다.
l int getItemCount(): 메뉴에 추가된 메뉴 아이템의 개수를 얻습니다.
l void insert(MenuItem menuitem, int index): 주어진 인덱스에 메뉴 아이템을 추가합니다.
l void insert(String label, int index): 주어진 인덱스에 주어진 이름의 메뉴 아이템을 추가합니다.
l void insertSeparator(int index): 주어진 인덱스에 메뉴 분리자를 추가합니다.
l boolean isTearOff(): 이 메뉴가 tear-off 메뉴인지를 얻습니다.
l void remove(int index): 주어진 인덱스에 해당하는 메뉴 아이템을 제거합니다.
l void remove(MenuComponent item): 주어진 메뉴 아이템을 제거합니다.
l void removeAll(): 등록된 모든 메뉴 아이템들을 제거합니다.
사. 팝업메뉴(PopupMenu) 컴포넌트
PopupMenu 클래스는 Menu 클래스를 상속하는 하위클래스로서, 팝업메뉴 컴포넌트를 dnl한 기능을 제공해 줍니다. 윈도우를 사용하는 사용자라면, 마우스의 오른쪽 버튼을 누르면 나타나는 팝업메뉴를 많이 보았을 것입니다. 이러한 팝업메뉴는 일반 메뉴와 같은 모양이지만, 한 가지 차이점은 사용자가 메뉴를 원할 때 마우스의 오른쪽 버튼을 누르는 것과 같이 원하는 때에 갑자기 화면상의 특정 위치에 나타나게 할 수 있다는 것입니다. 이러한 팝업메뉴 컴포넌트는 메뉴와 같이 메뉴바에서도 사용될 수 있는데, 이 때 주의할 점은 PopupMenu 객체의 show 메소드를 호출할 수 없다는 것입니다. 그리고, 일반적으로 메뉴를 메뉴바에 등록시켜주는 것처럼 팝업메뉴를 팝업메뉴가 나타날 컴포넌트에 등록을 시켜주어야 합니다.
import java.awt.*; public class PopupMenuTest extends Frame { PopupMenu popupMenu = new PopupMenu("Popup"); public PopupMenuTest() { popupMenu.add(new MenuItem("Undo")); MenuItem redoMenu = new MenuItem("Redo"); redoMenu.setEnabled(false); popupMenu.add(redoMenu); popupMenu.addSeparator(); Menu editMenu = new Menu("Edit"); editMenu.add(new MenuItem("Cut")); editMenu.add(new MenuItem("Copy")); MenuItem pasteMenu = new MenuItem("Paste"); pasteMenu.setEnabled(false); editMenu.add(pasteMenu); popupMenu.add(editMenu); popupMenu.addSeparator(); MenuItem quit = new MenuItem("Quit"); popupMenu.add(quit); add(popupMenu); } public static void main(String args[]) { PopupMenuTest f = new PopupMenuTest(); f.setTitle("PopupMenu"); f.setSize(300, 200); f.setVisible(true); f.popupMenu.show(f, 10, 10); } } /* * Results: D:\AIIT\JAVA\Working\08>java PopupMenuTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 23. PopupMenuTest.java>
팝업메뉴 컴포넌트의 기능을 제공해 주기 위한 PopupMenu 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l PopupMenu(): 팝업메뉴를 생성합니다.
l PopupMenu(String label): 주어진 이름을 갖는 팝업메뉴를 생성합니다.
l void show(Component origin, int x, int y): 팝업메뉴를 주어진 컴포넌트의 해당 위치에 나타나게 합니다.
l 메뉴를 생성하는 것은, Menu 클래스를 상속하는 하위클래스이므로 메뉴 컴포넌트에서와 같습니다.
아. 메뉴단축키(MenuShortcut) 컴포넌트
메뉴단축키 컴포넌트의 기능을 제공해 주기 위한 MenuShortcut 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l MenuShortcut(int key): 주어진 키에 대한 메뉴 메뉴단축키 객체를 생성합니다.
l MenuShortcut(int key, boolean useShiftModifier): 주어진 키에 대한 메뉴 메뉴단축키 객체를 생성합니다.
l int getKey(): 키 코드(raw keycode) 값을 얻습니다.
l boolean usesShiftModifier(): 메뉴 메뉴단축키 객체가 SHIFT 키를 사용하는지 여부를 설정합니다.
다음에 나오는 자바 프로그램은 메뉴 아이템에 메뉴단축키를 연결하는 간단한 예를 보여주고 있습니다.
import java.awt.*; class MenuShortcutTest extends Frame { public MenuShortcutTest() { setLayout(new FlowLayout()); MenuBar menuBar; Menu fileMenu, editMenu, viewMenu, helpMenu; MenuItem newItem, openItem, saveItem, saveAsItem; MenuShortcut saveShortcut, saveAsShortcut; menuBar = new MenuBar(); setMenuBar(menuBar); fileMenu = new Menu("File"); menuBar.add(fileMenu); newItem = new MenuItem("New", new MenuShortcut('n')); fileMenu.add(newItem); openItem = new MenuItem("Open"); openItem.setShortcut(new MenuShortcut('O')); fileMenu.add(openItem); fileMenu.addSeparator(); saveShortcut = new MenuShortcut(KeyEvent.VK_S); saveItem = new MenuItem("Save", saveShortcut); fileMenu.add(saveItem); saveAsShortcut = new MenuShortcut('A', true); saveAsItem = new MenuItem("Save As", saveAsShortcut); fileMenu.add(saveAsItem); editMenu = new Menu("Edit"); menuBar.add(editMenu); viewMenu = new Menu("View"); menuBar.add(viewMenu); helpMenu = new Menu("Help"); menuBar.setHelpMenu(helpMenu); } public static void main(String args[]) { MenuShortcutTest f = new MenuShortcutTest(); f.setSize(200, 60); // pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java MenuTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 24. MenuTest.java>
위의 자바 프로그램을 실행 시킨 후, ALT 키 또는 F10 키를 누르면 메뉴로 이동하여 메뉴를 선택할 수 있습니다. 단축 키를 등록하기 위해, 해당 키의 문자를 직접 입력할 수도 있고, 'KeyEvent.VK_'와 키를 주면 되는데 만약 'A' 키라면 KeyEvent.VK_A라고 주면 됩니다. 이렇게 하면, CTRL 키와 조합으로 메뉴단축키를 생성하게 됩니다. 마지막으로, SHIFT 키와 함께 메뉴단축키로 지정하고자 한다면, useShiftModifier 값을 true로 설정해 주면 됩니다.
6. 그래픽스
가. 그래픽스(Graphics) 클래스
Graphics 클래스는 자바 프로그램이 오프-스크린(off-screen) 이미지는 물론 다양한 디바이스 상에 나타나는 컴포넌트에 그릴 수 있도록 해 주는 그래픽스 컨텍스트(graphics context)를 위한 추상적인 기본 클래스입니다. 그래픽스 객체는 자바가 지원하는 기본 랜더링을 하기 위해 필요한 상태 정보들을 가지고 있고, 이 상태 정보는 다음과 같은 속성(property)를 포함하고 있습니다.
l 그리고자 하는 Component 객체
l 랜더링과 클리핑 좌표를 위한 변환 시작점(translation origin for rendering and clipping coordinates)
l 현재 클립(clip)
l 현재 컬러(color)
l 현재 폰트(font)
l 현재 논리적인 픽셀 연산 기능(XOR or Paint)
l 현재 XOR 색깔(setXORMode(java.awt.Color))
자바 그래픽스에서 그리거나 글씨는 쓰는 등의 작업은 항상 현재 컬러, 현재 페인트 모드(paint mode), 그리고 현재 폰트를 이용하여 작업이 이루어집니다.
그래픽스 기능을 제공해 주기 위한 Graphics 클래스의 객체 생성자와 주요 메소드를 살펴보면 다음과 같습니다.
l abstract void clearRect(int x, int y, int width, int height): 주어진 사각형을 배경색으로 지웁니다.
l abstract void clipRect(int x, int y, int width, int height): 주어진 사각형을 잘라서 현재 클립에 저장합니다. (Intersects the current clip with the specified rectangle.)
l abstract void copyArea(int x, int y, int width, int height, int dx, int dy): 컴포넌트의 주어진 영역을 dx와 dy 거리만큼에 복사합니다.
l void draw3DRect(int x, int y, int width, int height, boolean raised): 주어진 크기와 모양(나오거나 들어간 모양)을 갖는 3D 사각형을 그립니다.
l abstract void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle): 주어진 크기의 사각형에 해당하는 호를 그리는데, 시작 각부터 주어진 각만큼의 크기를 갖는 호를 그립니다.
l void drawBytes(byte[] data, int offset, int length, int x, int y): 현재 폰트와 컬러를 이용하여 주어진 바이트 배열에 있는 문자열을 해당 위치에 그립니다.
l void drawChars(char[] data, int offset, int length, int x, int y): 현재 폰트와 컬러를 이용하여 주어진 문자 배열에 있는 문자열을 해당 위치에 그립니다.
l abstract void drawLine(int x1, int y1, int x2, int y2): (x1, y1)에서 (x2, y2)까지의 라인을 그립니다.
l abstract void drawOval(int x, int y, int width, int height): 주어진 사각형에 맞는 타원을 그립니다.
l abstract void drawPolygon(int[] xPoints, int[] yPoints, int nPoints): 주어진 좌표들을 꼭지점으로 하는 다각형을 그립니다.
l void drawPolygon(Polygon p): 주어진 좌표들을 꼭지점으로 하는 다각형을 그립니다.
l abstract void drawPolyline(int[] xPoints, int[] yPoints, int nPoints): 주어진 좌표들을 연결하는 라인을 그립니다.
l void drawRect(int x, int y, int width, int height): 주어진 사각형을 그립니다.
l abstract void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight): 주어진 조건에 해당하는 둥근 사각형을 그리는데, 각의 너비와 높이에 맞게 둥글게 처리합니다.
l abstract void drawString(String str, int x, int y): 현재 폰트와 컬러를 사용하여 주어진 문자열을 그립니다.
l void fill3DRect(int x, int y, int width, int height, boolean raised): 3D 사각형을 그려 현재 컬러로 채웁니다.
l abstract void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle): 부채꼴 호를 그려 채웁니다.
l abstract void fillOval(int x, int y, int width, int height): 다원을 그려 채웁니다.
l abstract void fillPolygon(int[] xPoints, int[] yPoints, int nPoints): 다각형을 채웁니다.
l void fillPolygon(Polygon p): 다각형을 채웁니다.
l abstract void fillRect(int x, int y, int width, int height):사각형을 채웁니다.
l abstract void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight): 둥근 사각형을 채웁니다.
l abstract Shape getClip(): 현재 클립 영역을 얻습니다.
l abstract Rectangle getClipBounds(): 현재 클립 영역의 사각형 바운드를 얻습니다.
l Rectangle getClipBounds(Rectangle r): 현재 클립 영역의 사각형 바운드를 얻습니다.
l Rectangle getClipRect(): getClipBounds() 메소드로 바뀌었습니다.
l abstract Color getColor(): 현재 컬러를 얻습니다.
l abstract Font getFont(): 현재 폰트를 얻습니다.
l FontMetrics getFontMetrics(): 현재 폰트의 폰트 매트릭스를 얻습니다.
l abstract FontMetrics getFontMetrics(Font f): 주어진 폰트에 대한 폰트 매트릭스를 얻습니다.
l boolean hitClip(int x, int y, int width, int height): 주어진 사각형이 현재 클립 영역의 테두리와 겹치는 지를 얻습니다.
l abstract void setClip(int x, int y, int width, int height): 주어진 사각형으로 현재 클립을 설정합니다.
l abstract void setClip(Shape clip): 주어진 사각형으로 현재 클립을 설정합니다.
l abstract void setColor(Color c): 주어진 컬러로 현재 컬러를 설정합니다.
l abstract void setFont(Font font): 주어진 폰트로 현재 폰트를 설정합니다.
l abstract void setPaintMode(): 현재 컬러로 페인트 모드를 설정합니다.
l abstract void setXORMode(Color c1): 현재 컬러와 주어진 컬러를 이용하여 페인트 모드를 설정합니다.
다음에 나오는 자바 프로그램은 그래픽스 객체를 이용하여 캔버스 컴포넌트에 여러가지 도형을 그리는 예를 보여주고 있습니다.
import java.awt.*; public class GraphicsTest extends Frame { public GraphicsTest() { add(new Canvas() { public void paint(Graphics g) { g.setColor(Color.red); g.draw3DRect( 0, 0, 46, 36, true); g.draw3DRect( 50, 0, 46, 36, false); g.drawOval(150, 0, 46, 36); g.drawArc(200, 0, 46, 36, 0, 300); int x1[] = new int[] { 250, 300, 273 }; int y1[] = new int[] { 0, 0, 36 }; g.drawPolygon(x1, y1, x1.length); int x2[] = new int[] { 300, 350, 323 }; int y2[] = new int[] { 0, 0, 36 }; g.drawPolygon(new Polygon(x2, y2, x2.length)); int x3[] = new int[] { 350, 400, 373 }; int y3[] = new int[] { 0, 0, 36 }; g.drawPolyline(x3, y3, x3.length); g.setColor(Color.blue); g.fill3DRect( 0, 40, 46, 36, true); g.fill3DRect( 50, 40, 46, 36, false); g.fillOval(150, 40, 46, 36); g.fillArc(200, 40, 46, 36, 0, 300); int x4[] = new int[] { 250, 300, 273 }; int y4[] = new int[] { 40, 40, 76 }; g.fillPolygon(x4, y4, x4.length); int x5[] = new int[] { 300, 350, 323 }; int y5[] = new int[] { 40, 40, 76 }; g.fillPolygon(new Polygon(x5, y5, x5.length)); g.drawLine(350, 40, 396, 76); g.setColor(Color.black); byte[] b = new byte[] { g.drawBytes(b, 0, b.length, 10, 85); char[] c = new char[] { 'H','e','l','l','o',',',' ','J','a','v','a','!' }; g.drawChars(c, 0, c.length, 10, 100); g.drawString("Hello, Java graphics!", 10, 115); g.setColor(Color.lightGray); g.drawRect( 0, 120, 46, 36); g.drawRoundRect( 50, 120, 46, 36, 10, 10); g.fillRect(100, 120, 46, 36); g.fillRoundRect(150, 120, 46, 36, 10, 10); g.setColor(Color.blue); g.copyArea( 0, 0, 300, 100, 50, 160); g.drawRect( 50, 160, 300, 100); g.clearRect(80, 180, 250, 30); } }); } public static void main(String args[]) { GraphicsTest f = new GraphicsTest(); f.setTitle("Graphics"); f.setSize(420, 290); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java GraphicsTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 25. GraphicsTest.java>
위의 자바 예제에서는 자바 그래픽스에서 제공해 주는 여러가지 도형 그리는 메소드를 이용하여 도형들을 그려보았고, 그래픽스 영역에 대한 복사와 지우기도 하여 보았습니다. 그래픽스 객체는 모든AWT 컴포넌트가 가지고 있습니다. 이 그래픽스 객체를 얻기 위해서 각 컴포넌트의 getGraphics 메소드를 호출하거나, 그래픽스 관련 메소드에 전달된 그리기 관련 메소드에 전달된 그래픽스 객체를 이용하면 됩니다.
그리고, 현재 사용할 수 있는 스크린의 크기와 해상도를 알기 위해서는 Toolkit 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l static Toolkit getDefaultToolkit(): 디폴트 툴킷을 얻습니다.
l abstract int getScreenResolution(): 스크린 해상도(dots-per-inch)를 얻습니다.
l abstract Dimension getScreenSize(): 스크린의 크기를 얻습니다.
다음에 나오는 자바 프로그램은 Toolkit 클래스에서 제공해 주는 메소드를 이용하여 현재 스크린의 해상도와 크기를 알아보기 위한 예제입니다.
import java.awt.*; class ScreenTest { public static void main(String[] args) { Toolkit toolkit = Toolkit.getDefaultToolkit(); System.out.println("Resolution: "+toolkit.getScreenResolution()); System.out.println("Size: "+toolkit.getScreenSize()); } } /* * Results: D:\AIIT\JAVA\Working\08>java ScreenTest Resolution: 96 Size: java.awt.Dimension[width=1024,height=768] D:\AIIT\JAVA\Working\08> */ |
<프로그램 26. ScreenTest.java>
나. 컴포넌트의 그리기 메소드
자바의 모든 AWT 컴포넌트는 자신의 그리기 메소드를 가지고 있습니다. 그리고, 이러한 그리기 메소드는 사용자가 재정의하여 사용자가 원하는 그리기를 할 수 있습니다. 이렇게 Component 클래스에서컴포넌트의 그리기와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l Graphics getGraphics(): 이 컴포넌트를 위한 그래픽스 컨텍스트(graphics context) 객체를 생성합니다.
l void repaint(): 이 컴포넌트를 다시 그립니다. 내부적으로 update 메소드를 호출합니다.
l void repaint(int x, int y, int width, int height): 이 컴포넌트의 주어진 영역을 다시 그립니다. 내부적으로 update 메소드를 호출합니다.
l void repaint(long tm): 주어진 시간(tm 밀리초) 내에 컴포넌트를 다시 그립니다. 내부적으로 update 메소드를 호출합니다.
l void repaint(long tm, int x, int y, int width, int height): 주어진 시간(tm 밀리초) 내에 이 컴포넌트의 주어진 영역을 다시 그립니다. 내부적으로 update 메소드를 호출합니다.
l void update(Graphics g): 컴포넌트의 그리기를 업데이트 합니다.
l void paint(Graphics g): 이 컴포넌트를 그립니다.
l void paintAll(Graphics g): 이 컴포넌트와 모든 하위컴포넌트를 그립니다.
위와 같이 Component 클래스에서는 세 가지 종류의 그리기 메소드들을 제공해 주고 있습니다. 이 때, 자바 프로그램에서는 컴포넌트의 영역을 다시 그리고자 할 때 repaint 메소드를 호출하면 되고, 또는 컴포넌트의 크기가 사용자에 의해 변경되거나 아이콘 상태에서 정상적인 윈도우 상태로 변하게 될 때 컴포넌트 내부를 다시 그려주어야 되는데, 이를 위해 repaint 메소드가 내부적으로 호출됩니다. 이 때 내부적으로 이루어지는 작업을 보면 다음과 같습니다.
l repaint 메소드: update(Graphics g) 메소드를 시스템 내부적으로 호출합니다.
l update 메소드: 해당 컴포넌트의 바탕색으로 컴포넌트의 영역을 지웁니다. 그리고 paint(Graphics g) 메소드를 호출합니다.
l paint(Graphics g): 그리기 작업을 수행합니다.
따라서, 자바 프로그래머는 자신이 어떤 컴포넌트에 그려야 할 작업이 있으면, 이를 해당 컴포넌트의 paint 메소드 내에 위치시키면 됩니다. 그리고, 컴포넌트가 다시 그려지기를 원한다면, 해당 컴포넌트의rapaint 메소드 중 하나를 호출하면 됩니다. 그리고, 디폴트 update 메소드는 컴포넌트의 바탕색으로 먼저 그리기 영역을 지우고, paint 메소드를 호출하게 되므로, 그리기를 반복하는 애니메이션의 경우 지우고 그리기를 반복하므로 깜박거리는 현상이 발생하게 됩니다. 애니메이션에 대해서는 다음에 더욱 자세히 하기로 하겠습니다.
다. 컬러(Color)
Component 클래스에서 컬러와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l ColorModel getColorModel(): 컴포넌트를 디스플레이 장치에 디스플레이하기 위한 컬러모델(ColorModel)을 얻습니다.
l Color getBackground(): 컴포넌트의 배경색을 얻습니다.
l void setBackground(Color c): 컴포넌트의 배경색을 설정합니다.
l Color getForeground(): 컴포넌트의 전경색을 얻습니다.
l void setForeground(Color c): 컴포넌트의 전경색을 설정합니다.
Color 클래스에서 컬러와 관련하여 제공해 주는 클래스 변수와 주요 메소드를 살펴보면 다음과 같습니다.
l static Color black: 검정색(black) 상수 컬러
l static Color blue: 파랑색(blue) 상수 컬러
l static Color cyan: 하늘색(cyan) 상수 컬러
l static Color darkGray: 어두운 회색(dark gray) 상수 컬러
l static Color gray: 회색(gray) 상수 컬러
l static Color green: 초록색(green) 상수 컬러
l static Color lightGray: 밝은 회색(light gray) 상수 컬러
l static Color magenta: 갈색(magenta) 상수 컬러
l static Color orange: 오랜지색(orange) 상수 컬러
l static Color pink: 핑크색(pink) 상수 컬러
l static Color red: 빨강색(red) 상수 컬러
l static Color white: 햐양색(white) 상수 컬러
l static Color yellow: 노랑색(yellow) 상수 컬러
l Color(float r, float g, float b): 주어진 red, green, blue 값(0.0 - 1.0 사이)을 갖는 컬러 객체를 생성합니다.
l Color(float r, float g, float b, float a): 주어진 red, green, blue, alpha 값(0.0 - 1.0 사이)을 갖는 컬러 객체를 생성합니다.
l Color(int rgb): 주어진 비트조합에 해당하는 컬러 객체를 생성합니다. (red: 16-23 비트, green: 8-15 비트, blue: 0-7 비트)
l Color(int rgba, boolean hasalpha): 주어진 조합네 해당하는 컬러 객체를 생성합니다. (alpha: 24-31 비트, red: 16-23 비트, green: 8-15 비트, blue: 0-7비트)
l Color(int r, int g, int b): 0부터 255 사이의 rgb 값에 해당하는 컬러 객체를 생성합니다.
l Color(int r, int g, int b, int a): 0부터 255 사이의 rgba 값에 해당하는 컬러 객체를 생성합니다.
l Color brighter(): 이 객체가 가진 색의 밝은 색을 얻습니다.
l Color darker(): 이 객체가 가진 색의 어두운 색을 얻습니다.
l int getAlpha(): 이 색의 alpha 값을 얻습니다.
l int getBlue():이 색의 blue 값을 얻습니다.
l int getGreen():이 색의 green 값을 얻습니다.
l int getRed():이 색의 red 값을 얻습니다.
l int getRGB(): 디폴트 sRGB 컬러 모델(ColorModel)에서 RGB 값을 얻습니다.
다음에 나오는 자바 프로그램은 컬러 객체를 이용하여 컴포넌트의 컬러를 변경하는 예를 보여주고 있습니다.
import java.awt.*; class ColorTest extends Frame { Panel p; Button b1, b2; Color bc, fc; public ColorTest() { Panel p = new Panel(); Button b1 = new Button("OK"); Button b2 = new Button("Cancel"); setBackground(Color.blue); setForeground(Color.lightGray); p.setBackground(Color.magenta); p.setForeground(Color.red); b2.setBackground(Color.blue); b2.setForeground(Color.yellow); bc = b2.getBackground(); fc = b2.getForeground(); add(p); p.add(b1); p.add(b2); pack(); } public static void main(String[] args) { ColorTest f = new ColorTest(); f.setTitle("Color"); f.setVisible(true); System.out.println("bc(r,g,b,a): (" + f.bc.getRed() + "," + f.bc.getGreen() + "," + f.bc.getBlue() + "," + f.bc.getAlpha() + ")"); System.out.println("fc(r,g,b,a): (" + f.fc.getRed() + "," + f.fc.getGreen() + "," + f.fc.getBlue() + "," + f.fc.getAlpha() + ")"); } } /* * Results: D:\AIIT\JAVA\Working\08>java ColorTest bc(r,g,b,a): (0,0,255,255) fc(r,g,b,a): (255,255,0,255) D:\AIIT\JAVA\Working\08> */ |
<프로그램 27. GraphicsTest.java>
위의 자바 프로그램을 실행시킨 후 윈도우가 나타났을 때 윈도우의 크기를 변경해 보면, 배경색이 파랑색으로 칠해지는 것을 볼 수 있습니다. 이는 프레임의 배경색으로 파랑색을 설정했기 때문입니다.
라. 팔레트 제작
자바에서는 다음 그림에서와 같이 32비트를 이용하여 이미지의 한 픽셀을 나타내며, 그래픽과 이미지를 나타내기 위해 컬러 모델을 이용합니다.
알파는 픽셀의 투명한 정도를 나타내고, 나머지는 기존의 RGB를 나타내는 것입니다. 그리고 이러한 픽셀의 색은 컬러 모델에 의해서 처리됩니다. 컬러 모델에는 다이렉트 컬러 모델과 인덱스 컬러 모델이있습니다. 이 중 인덱스 컬러 모델은 우리가 16색, 64색, 256색 등과 같이 색의 수를 나타낼 때 사용하던 팔레트, 즉 컬러 맵을 이용할 수 있도록 해 주는 방법입니다. 따라서 픽셀 값은 실제 컬러의 ARGB값이아니라, 컬러 맵에서의 인덱스를 나타내는 것입니다.
인덱스 컬러 모델을 자바에서 이용하기 위해서는 다음과 같은 순서로 작업을 해 주면 됩니다. 먼저, 원하는 컬러 및 개수로 이루어진 컬러 맵을 만듭니다. 이 컬러 맵은 Alpha, Red, Green, Blue 각각의 값을 배열로 가지고 있습니다. IndexColorModel을 생성하기 위해, 컬러 맵의 인덱스를 저장하기 위한 픽셀의 넓이를 계산해야 하는데, 다음과 같은 수식을 사용합니다.
이제, 그래디언트 이미지에 수평적으로 각각의 값을 배치하기 위해, 다음의 공식을 사용하면 됩니다.
마지막으로, 이렇게 메모리에 만든 이미지를, MemoryImageSource 메소드를 이용하여 이미지를 생성합니다. 다음은 위의 과정을 잘 보여주는 간단한 예제 프로그램입니다.
import java.awt.*; import java.awt.event.*; import java.awt.image.*; public class ColorMapTest extends Frame { static int SIZEX = 256,SIZEY = 32; static int COLOR_NUM = 256; byte[][] grayMap; IndexColorModel grayModel; Image img; public void MakeGrayColorMap() { grayMap = new byte[3][COLOR_NUM]; for(int i=0;i<3;i++) { for(int j=0;j<256;j++) { grayMap[i][j] = (byte)j; // Grayscale (r,g,b) } } addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); } public void SetGrayColorMap() { int bits = (int)Math.ceil(Math.log(COLOR_NUM) / Math.log(2)); grayModel = new IndexColorModel(bits, COLOR_NUM, grayMap[0], grayMap[1], grayMap[2]); } public void MakeColorMapImage() { int pixels[] = new int[SIZEX * SIZEY]; int index=0; for(int y=0;y<SIZEY;y++) { for(int x=0;x<SIZEX;x++) { pixels[index++] = (y * COLOR_NUM) / SIZEY; // y축 방향으로 변화 } } // Create the image img = createImage(new MemoryImageSource(SIZEX, SIZEY, grayModel, pixels, 0, SIZEX)); setBackground(Color.red); } public void paint(Graphics g) { g.drawImage(img, 8, 28, this); super.paint(g); } public static void main(String[] argv) { ColorMapTest f = new ColorMapTest(); f.MakeGrayColorMap(); f.SetGrayColorMap(); f.MakeColorMapImage(); f.setTitle("ColorMap"); f.setSize(272,70); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java ColorMapTest D:\AIIT\JAVA\08> */ |
<프로그램 28. ColorMapTest.java>
마. 폰트(Font)
Component 클래스에서 폰트와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l Font getFont(): 이 컴포넌트의 폰트를 얻습니다.
l void setFont(Font f): 이 컴포넌트의 폰트를 주어진 폰트로 설정합니다.
l FontMetrics getFontMetrics(Font font): 주어진 폰트의 폰트 메트릭스를 얻습니다.
자바에서는 폰트가 갖는 여러가지 기능을 위해 Font 클래스를 제공해 주고 이쏘, 폰트를 다루기 위해 자바에서는 다음과 같은 두 가지 용어를 사용합니다.
l 문자 또는 기호(character): 문자(letter0 또는 숫자(number)와 같이 아이템을 나타내는 부호 또는 기호(symbol)를 'character'라 합니다. 예를 들어, 화면상에 디스플레이 하려는 소문자 (g)는 문자라 할수 있습니다.
l 모양 또는 상형문자(glyph): 문자를 쓴다는 것은 화면상에 그리는 것을 의미하는데, 이 때 화면상에 나타날 모양을 'glyph'라 합니다.
위와 같이 폰트는 개념적으로 두 가지로 구분이 되며, 이 때 문자 인코딩(character encoding)이란 'character' 코드를 폰트 내의 'glyph' 코드로 변환하기 위한 변환 테이블(conversion table)이라 할 수 있습니다. 이때, 'character'와 'glyph' 간에는 항상 1대 1의 변환이 이루어지는 것은 아닙니다. 다음과 같은 경우를 들 수 있습니다.
l 악센트 문자(à, á, â, ã, ä, å): 액센트를 갖는 소문자 a(lowercase-a acute)는 소문자 a(lowercase-a)와 액센트(acute) 등 두 가지의 'glyph'를 갖습니다.
l 합자(æ, ij, ǽ, , [1], fl): fi는 하나의 'glyph'를 갖지만, f와 i 등 두 가지의 'character'를 갖습니다.
폰트는 다음과 같은 세 가지 서로 다른 이름을 갖습니다.
l 논리적 폰트 이름(logical font name): java.awt.Font에 의해 사용되는 것과 같은 이름입니다.
l 폰트 모양 이름(font face name 또는 font name): 'Helvetica Bold', 'Helvetica Italic' 등과 같이 폰트의 특별한 모양을 알 수 있도록 나타내는 이름입니다.
l 패밀리 이름(family name): 'Helvetica'와 같이 폰트의 이름을 나타내며, 이 패밀리 이름과 폰트의 모양을 합쳐 폰트 모양 이름을 나타낼 수 있습니다.
Font 클래스가 제공해 주는 클래스 변수와 주요 메소드를 살펴보면 다음과 같습니다.
l static int PLAIN: 플레인 스타일 값
l static int BOLD: 볼드 스타일 값
l static int ITALIC: 이탤릭 스타일 값
l static int CENTER_BASELINE: 중국어, 일본어, 그리고 한국어 등의 문자를 위한 베이스라인입니다.
l static int HANGING_BASELINE: Devanigiri 문자를 위한 베이스라인입니다.
l static int ROMAN_BASELINE: 대부분의 Roman 문자를 위한 베이스라인입니다.
l Font(String name, int style, int size): 주어진 조건에 따라 폰트를 생성합니다.
l boolean canDisplay(char c): 주어진 문자가 디스플레이 가능한 지를 얻습니다.
l int canDisplayUpTo(char[] text, int start, int limit): 문자 배열 내에 있는 문자들이 모두 디스플레이 가능한지를 얻습니다.
l int canDisplayUpTo(String str): 주어진 문자열이 디스플레이 가능한지를 얻습니다.
l byte getBaselineFor(char c): 주어진 문자를 디스플레이하기 적당한 베이스 라인을 얻습니다.
l String getFamily():이 폰트의 패밀리 이름을 얻습니다.
l String getFontName(): 이 폰트의 이름을 얻습니다.
l float getItalicAngle(): 이 폰트의 이탤릭 각을 얻습니다.
l String getName(): 이 폰트의 논리적 이름을 얻습니다.
l int getSize(): 이 폰트의 크기를 얻습니다.
l int getStyle(): 이 폰트의 스타일을 얻습니다.
l boolean hasUniformLineMetrics(): 이 폰트가 동일한 라인 메트릭스를 갖는가를 얻습니다.
l boolean isBold(): 스타일이 볼드인지를 얻습니다.
l boolean isItalic(): 스타일이 이탤릭인지를 얻습니다.
l boolean isPlain(): 스타일이 플레인인지를 얻습니다.
l static Font decode(String str): 주어진 이름의 폰트를 얻습니다.
l Font deriveFont(float size): 현재 폰트에 주어진 새로운 크기를 적용하여 새로운 폰트를 얻습니다.
l Font deriveFont(int style): 현재 폰트에 주어진 새로운 스타일을 적용하여 새로운 폰트를 얻습니다.
l Font deriveFont(int style, float size): 현재 폰트에 주어진 새로운 크기와 스타일을 적용하여 새로운 폰트를 얻습니다.
FontMetrics 클래스는 특정 폰트(particular font)가 특정 스크린(particular screen) 상에 나타나게(rendering) 하는데 대한 정보를 갖는 폰트 메트릭스 객체(font metrics object)를 정의하고 있습니다.
<그림 5. 폰트 내에 있는 문자가 갖는 속성>
만약, AWT를 이용하여 한 문자를 (x,y) 위치에 그리려고 한다면, 위의 그림에 나타나는 것처럼 해당 위치에 문자를 그립니다. 이 때, 각 문자는 그림에 나타나는 것과 같이, 다음과 같은 속성을 갖습니다.
l 기준선(baseline): 문자열을 그리기 위한 기준선(문자를 그릴 때 y위치를 기준선에 맞춤)입니다.
l 어센트(ascent): 문자의 기준선 아래에 있는 부분의 크기입니다.
l 디센트(descent): 문자의 기준선 위에 있는 부분의 크기입니다.
l 증가 너비(advance width): 이 문자를 그린 후, 다음 문자를 그릴 위치를 위해 증가해야 할 크기입니다. 위의 그림에서는 문자를 둘러싸고 있는 테두리 박스의 너비와 같습니다. 그리고, 증가 너비는오블리크(oblique)와 이탤릭(italic) 폰트의 경우(p) 일반 경우(p)보다, 증가 너비는 약간 커집니다.
문자와 마찬가지로, 문자 배열과 문자열 역시 위와 같은 어센트(ascent), 디센트(descent), 그리고 증가 너비(advance width) 등과 같은 속성을 갖습니다. 문자 배열과 문자열의 어센트는 문자 배열 또는 문자열내에 있는 문자의 어센트 중 가장 큰 값을 나타내고, 문자 배열과 문자열의 디센트는 문자 배열 또는 문자열 내에 있는 문자의 디센트 중 가장 큰 값을 나타내고, 마지막으로 문자 배열과 문자열의 디센트는문자 배열 또는 문자열 내에 있는 문자들의 증가 너비를 모두 합한 것입니다.
FontMetrics 클래스가 제공해 주는 클래스 변수와 주요 메소드를 살펴보면 다음과 같습니다.
l int bytesWidth(byte[] data, int off, int len): 주어진 배열 객체의 내용을 디스플레이 하는데 드는 너비를 얻습니다.
l int charsWidth(char[] data, int off, int len):: 주어진 문자 객체의 내용을 디스플레이 하는데 드는 너비를 얻습니다.
l int charWidth(char ch): 주어진 문자의 너비를 얻습니다.
l int charWidth(int ch): 주어진 문자의 너비를 얻습니다.
l int getAscent(): 이 폰트 매트릭스(FontMetrics) 객체가 나타내는 폰트의 ascent를 얻습니다.
l int getDescent(): 이 폰트 매트릭스(FontMetrics) 객체가 나타내는 폰트의 descent를 얻습니다.
l Font getFont(): 이 폰트 매트릭스(FontMetrics) 객체가 나타내는 폰트의 폰트를 얻습니다.
l int getHeight(): 텍스트 라인의 표준 높이를 얻습니다.
l int getLeading(): 이 폰트 매트릭스(FontMetrics) 객체가 나타내는 폰트의 leading을 얻습니다.
l int getMaxAdvance(): 이 폰트 내에 있는 문자 중 최대 너비를 얻습니다.
l int getMaxAscent(): 이 폰트 내에 있는 문자 중 최대 ascent를 얻습니다.
l int getMaxDecent(): getMaxDescent() 메소드로 바뀌었습니다.
l int getMaxDescent(): 이 폰트 내에 있는 문자 중 최대 descent를 얻습니다.
l Rectangle2D getStringBounds(char[] chars, int beginIndex, int limit, Graphics context): 주어진 그래픽스 컨텍스트 내에서의 주어진 문자들이 보여지기 위해 필요한 바운드를 얻습니다.
l Rectangle2D getStringBounds(String str, Graphics context): 주어진 그래픽스 컨텍스트 내에서의 주어진 문자열이 보여지기 위해 필요한 바운드를 얻습니다.
l Rectangle2D getStringBounds(String str, int beginIndex, int limit, Graphics context): 주어진 그래픽스 컨텍스트 내에서의 주어진 문자열이 보여지기 위해 필요한 바운드를 얻습니다.
l int[] getWidths(): 폰트 내에 있는 처음 256 개의 문자들이 갖는 너비를 배열로 얻습니다.
l int stringWidth(String str): 문자열을 이 폰트 내에 있는 문자들로 보여줄 때 필요한 너비를 얻습니다.
시스템에서 사용하는 폰트를 얻기 위해, Toolkit 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l static Toolkit getDefaultToolkit(): 디폴트 툴킷을 얻습니다.
l abstract String[] getFontList():
GraphicsEnvironment.getAvailableFontFamilyNames() 메소드로
바뀌었습니다.
l abstract FontMetrics getFontMetrics(Font font): 디폴트 스크린을 위한 정수 메트릭스를 얻습니다.
시스템에서 사용할 수 있는 폰트에 대한 정보를 얻기 위해 GraphicsEnvironment 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l public static GraphicsEnvironment getLocalGraphicsEnvironment(): 그래픽 환경 객체(GraphicsEnvironment )를 얻습니다.
l abstract Font[] getAllFonts(): 이 그래픽 환경에서 사용가능한 모든 폰트들의 크기 1인 객체를 포함하고 있는 배열을 리턴합니다.
l abstract String[] getAvailableFontFamilyNames(): 이 그래픽 환경에서 사용가능한 모든 폰트 패밀리의 이름을 포함하고 있는 배열을 리턴합니다.
l abstract String[] getAvailableFontFamilyNames(Locale l): 이 그래픽 환경에서 사용가능한 모든 폰트 패밀리의 지역화 이름(localized names)을 포함하고 있는 배열을 리턴합니다.
그래픽스 컨텍스트에서 현재 사용하고 있는 폰트에 대한 정보를 얻기 위해 Graphics 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l abstract Font getFont(): 현재 폰트를 얻습니다.
l FontMetrics getFontMetrics(): 현재 폰트의 폰트 매트릭스를 얻습니다.
l abstract FontMetrics getFontMetrics(Font f): 주어진 폰트에 대한 폰트 매트릭스를 얻습니다.
다음에 나오는 자바 프로그램은 위에서 살펴 본 클래스에서 제공해 주는 메소드를 이용하여 폰트를 테스트 한 예제입니다.
import java.awt.*; class FontTest extends Frame { Font f1, f2, f3; public FontTest() { f1 = new Font("Verdana", Font.PLAIN, 16); f2 = new Font("Times New Roman", Font.BOLD+Font.ITALIC, 24); f3 = new Font("SansSerif", Font.ITALIC, 16); } public void paint(Graphics g) { int x, y, h1, h2; FontMetrics fm; x = getInsets().left + 4; y = getInsets().top + 4; h1 = getFontMetrics(f1).getHeight(); h2 = getFontMetrics(f2).getHeight(); y += (h1 > h2) ? h1: h2; fm = getFontMetrics(f1); g.setFont(f1); g.drawString("Hello, Java!", x, y); x += fm.stringWidth("Hello, Java!"); g.setFont(f2); g.drawString("Hello, Java!", x, y); fm = getFontMetrics(f3); x = getInsets().left+4; y += fm.getHeight(); g.setFont(f3); g.drawString("Hello, Java!", x, y); } public static void main(String[] args) { Toolkit toolkit = Toolkit.getDefaultToolkit(); // String[] fontList = toolkit.getFontList(); GraphicsEnvironment ge = String[] fontList = ge.getAvailableFontFamilyNames(); for(int i=0;i<fontList.length;i++) { Font f = Font.decode(fontList[i]); FontMetrics fm = toolkit.getFontMetrics(f); System.out.println(" FontList["+i+"]: "+fontList[i]); System.out.println("FontMetrics["+i+"]: "+fm); } FontTest f = new FontTest(); f.setTitle("Font"); f.setSize(300, 100); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>FontTest FontList[0]: Arial FontMetrics[0]: FontList[1]: Arial Black FontMetrics[1]: ... FontList[50]: Webdings FontMetrics[50]: FontList[51]: Wingdings FontMetrics[51]: FontList[52]: ??? FontMetrics[52]: sun.awt.font.FontDesignMetrics[font=java.awt.Font[family=GulimChe,name= D:\AIIT\JAVA\Working\08> */ |
<프로그램 29. FontTest.java>
위의 자바 프로그램에서는 폰트를 생성하고, 폰트 메트릭스를 이요하여 폰트의 특성에 따라 화면상에 그리며, 그리고 시스템에서 제공해 주는 폰트에 대해 하나씩 살펴보고 있습니다. 이 때, 문자 또는 문자열을 그래픽스 컨텍스트를 이용하여 그릴 때, 그리고자 하는 시작 좌표와 x 또는 y 좌표의 증가분을 계산하는 방법에 대하여 자세히 살펴보기 바랍니다.
바. 커서(Cursor)
커서란 마우스의 포인터를 가리킵니다. 이러한 마우스 포인터를 자바 프로그램 상에서 변경하는 등의 작업을 할 수 있도록 하기 위해, Cursor 클래스에서 제공해 주는 주요 클래스 변수와 메소드를 살펴보면 다음과 같습니다.
l static int DEFAULT_CURSOR: 디폴트 커서 타입
l static int CROSSHAIR_CURSOR: crosshair 커서 타입
l static int HAND_CURSOR: hand 커서 타입
l static int MOVE_CURSOR: move 커서 타입
l static int TEXT_CURSOR: text 커서 타입
l static int WAIT_CURSOR: wait 커서 타입
l static int CUSTOM_CURSOR: 사용자 커서 타입
l static int N_RESIZE_CURSOR: north-resize 커서 타입
l static int NE_RESIZE_CURSOR: north-east-resize 커서 타입
l static int NW_RESIZE_CURSOR: north-west-resize 커서 타입
l static int S_RESIZE_CURSOR: south-resize 커서 타입
l static int SE_RESIZE_CURSOR: south-east-resize 커서 타입
l static int SW_RESIZE_CURSOR: south-west-resize 커서 타입
l static int E_RESIZE_CURSOR: east-resize 커서 타입
l static int W_RESIZE_CURSOR: west-resize 커서 타입
l Cursor(int type): 주어진 타입의 커서를 생성합니다.
l String getName(): 커서의 이름을 얻습니다.
l int getType(): 이 커서의 타입을 얻습니다.
l static Cursor getPredefinedCursor(int type): 주어진 타입의 정의된 커서를 얻습니다.
l static Cursor getDefaultCursor(): 시스템 디폴트 커서를 얻습니다.
l static Cursor getSystemCustomCursor(String name): 주어진 이름의 시스템 사용자 커서를 얻습니다.
Component 클래스에서 커서와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l Cursor getCursor():Gets the cursor set on this component.
l void setCursor(Cursor cursor): Sets the cursor image to the specified cursor.
다음에 나오는 자바 프로그램은 자바에서 미리 제공해 주고 있는 여러가지 커서에 대한 테스트 프로그램입니다.
import java.awt.*; class CursorTest extends Frame { public CursorTest() { Panel p = new Panel(new GridLayout(5, 4)); int[] type = new int[] { Cursor.DEFAULT_CURSOR, Cursor.CROSSHAIR_CURSOR, Cursor.HAND_CURSOR, Cursor.MOVE_CURSOR, Cursor.TEXT_CURSOR, Cursor.WAIT_CURSOR, Cursor.E_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR, Cursor.N_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR }; //, Cursor.CUSTOM_CURSOR }; setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); add(p); for(int i=0;i<type.length;i++) { Cursor cursor; Button button; cursor = Cursor.getPredefinedCursor(type[i]); button = new Button(cursor.getName()); button.setCursor(cursor); p.add(button); } } public static void main(String args[]) { CursorTest f = new CursorTest(); f.setTitle("Cursor"); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java CursorTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 30. CursorTest.java>
위의 프로그램에서는 각 버튼에 커서를 하나씩 연결해 놓았으므로, 마우스를 각 버튼으로 이동해 보면, 각 커서의 차이점을 알 수 있습니다.
사. 이미지(Image)
Image 클래스에서 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l abstract Graphics getGraphics(): 오프-스크린 이미지(off-screen image)를 그리기 위한 그래픽스 컨텍스트를 생성합니다.
l abstract ImageProducer getSource(): 이미지를 위한 픽셀들을 생성하는 이미지 생성자 객체를 얻습니다.
l abstract int getWidth(ImageObserver observer): 이미지의 너비를 얻습니다.
l abstract int getHeight(ImageObserver observer): 이미지의 높이를 얻습니다.
이미지 객체를 생성하기 위해, Toolkit 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l static Toolkit getDefaultToolkit(): 디폴트 툴킷을 얻습니다.
l abstract Image getImage(String filename): 주어진 파일에서 이미지를 얻습니다.
l abstract Image getImage(URL url): 주어진 URL에서 이미지를 얻습니다.
l abstract Image createImage(String filename): 주어진 파일에서 이미지를 얻습니다.
l abstract Image createImage(URL url): 주어진 URL에서 이미지를 얻습니다.
l Image createImage(byte[] imagedata): 주어진 바이트 배열 내에 저장되어 있는 이미지를 해석하여 이미지를 생성합니다.
l abstract Image createImage(byte[] imagedata, int imageoffset, int imagelength): 주어진 바이트 배열 내의 주어진 위치부터 길이만큼 저장되어 있는 이미지를 해석하여 이미지를 생성합니다.
l abstract Image createImage(ImageProducer producer): 주어진 이미지 생성자(ImageProducer)를 갖는 이미지를 생성합니다.
l abstract int checkImage(Image image, int width, int height, ImageObserver observer): 주어진 이미지가 디스플레이 되기 위해 생성될 때의 상태를 얻습니다.
l abstract int getScreenResolution(): 스크린 해상도(dots-per-inch)를 얻습니다.
l abstract Dimension getScreenSize(): 스크린의 크기를 얻습니다.
이미지 객체를 그리기 위해, Graphics 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l abstract boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
l abstract boolean drawImage(Image img, int x, int y, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
l abstract boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
l abstract boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
l abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
l abstract boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer): 주어진 조건에 맞게 이미지를 그립니다.
다음에 나오는 자바 프로그램은 위의 클래스들이 제공해 주는 이미지 관련 메소드들을 이용하여, 자바에서 제공해 주지 않는 이미지 버튼을 만들기 위한 예제 입니다.
import java.awt.*; import java.awt.event.*; class ImageButton extends Canvas { private Image currentImage; private Image normalImage; private Image normalOnImage; private Image actionImage; public ImageButton(String normal, String normalOn, String action) { MediaTracker tracker = new MediaTracker(this); normalImage = Toolkit.getDefaultToolkit().createImage(normal); normalOnImage = Toolkit.getDefaultToolkit().createImage(normalOn); actionImage = Toolkit.getDefaultToolkit().createImage(action); tracker.addImage(normalImage, 0); tracker.addImage(normalOnImage, 0); tracker.addImage(actionImage, 1); try { tracker.waitForAll(); } catch (InterruptedException e) { } init(normalImage, normalOnImage, actionImage); } public ImageButton(Image normalImage, Image normalOnImage, init(normalImage, normalOnImage, actionImage); } public void init(Image normal, Image normalOn, Image action) { normalImage = normal; normalOnImage = normalOn; actionImage = action; currentImage = normal; setSize(normal.getWidth(this), normal.getHeight(this)); addMouseListener(new MouseAdapter () { public void mousePressed(MouseEvent e) { currentImage = actionImage; repaint(); } public void mouseReleased (MouseEvent e) { currentImage = normalImage; repaint(); } public void mouseEntered(MouseEvent e) { currentImage = normalOnImage; repaint(); } public void mouseExited(MouseEvent e) { currentImage = normalImage; repaint(); } }); } public void paint(Graphics g) { g.drawImage(currentImage, 0, 0, this); } } class ImageButtonTest extends Frame { public ImageButtonTest() { setLayout(new FlowLayout()); add(new Button("Button")); add(new ImageButton("NormalButton.gif", "NormalOnButton.gif", } public static void main(String args[]) { ImageButtonTest f = new ImageButtonTest(); f.setSize(200, 150); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\Working\08>java ImageButtonTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 31. ImageButtonTest.java>
위의 자바 프로그램을 실행시키면, 결과의 가장 첫 화면이 나타납니다. 이 때, 이미지 버튼 내부로 마우스 커서가 들어가면, 두 번째 이미지 버튼으로 바뀌고, 마우스가 눌리게 되면 세 번째 이미지 버튼으로 바뀌게 됩니다. 물론, 지금은 자바에서 이미지를 다루는 방법에 초점을 두겠습니다. 그리고, 이미지를 생성(로딩)할 때, 사용한 메디아 크랙커(MediaTracker)에 대해서는 다로 다음에서 설명하겠고, 마우스의 동작을 처리하기 위한 마우스 이벤트 처리에 대해서는 뒷부분에서 자세히 다루기로 하겠습니다.
아. 미디어 트랙커(MediaTracker)
MediaTracker 클래스는 자바 프로그램 특히 애플릿에서 이미지 또는 오디오 클립 등과 같은 멀티미디어 객체를 많이 다루게 되는데, 이 때 각 미디어 객체의 상태를 가지고 있도록 하기 위한 기능들을 제공해 줍니다. (현재는 이미지 객체만을 지원합니다.) 특히, 애플릿이 미디어 객체를 많이 사용하거나 또는 크기가 큰 미디어 객체를 사용하게 될 때, 애플릿 코드는 미디어 객체보다 상대적으로 빨리 로딩될수 있습니다. 이 때, 애플릿은 미디어 객체가 제대로 로딩되기도 전에 미디어 객체를 사용하려 할 것입니다. 이렇게 될 경우, 자바에서는 NullPointerExeception과 같은 예외를 발생시키겠지요. 왜냐하면, 미디어 객체가 아직 로딩이 안된 상태이므로 null이기 때문입니다. 또는, 위의 자바 프로그램에서 처럼 이미지 버튼을 생성하려 할 때, 이미지 버튼의 크기를 설정해야 하는데, 이미지 객체가 아직 로딩이 덜 된상태라면, 이미지버튼의 크기는 (-1, -1)이 됩니다. 이럴 경우, 자바 프로그래머는 예상치 못한 결과를 얻게 됩니다. 따라서, 미디어 객체를 다루게 될 때, 그 미디어 객체의 로딩이 모두 완료된 상태에서 프로그램이 계속 진행이 되어야 합니다. 이를 위해, 자바에서는 미디어 트랙커(MediaTracker)를 제공해 주고 있습니다. 이러한 미디어 트랙커를 사용하는 순서는 다음과 같습니다.
l "MediaTracker tracker = new MediaTracker(this);": 먼저, MediaTracker 객체를 생성합니다.
l "tracker.addImage(normalImage, 0);": 상태 정보를 유지하고자 하는 미디어 객체를 미디어 크랙커 객체에 추가합니다. 이 때, 각 이미지에 고유 식별자(unique identifier)를 할당할 수 있고, 이 식별자 값은이미지가 사용될(fetched) 우선순위이거나, 이미지에 대한 우선순위에 따른 그룹을 설정하기 위해 사용될 수도 있습니다. 위의 예제에서는 두 개의 이미지 객체(normalImage, normalOnImage)에 대해0값을 나머지 이미지 객체(actionImage)에 대해서는 1의 값을 줌으로써 이미지 객체에 대한 그룹을 형성하고 우선순위를 준 것입니다.
l "tracker.waitForAll();": 원하는 또는 모든 이미지 객체가 로딩 될 때까지 기다립니다.
미디어 객체의 상태를 유지하기 위해 제공되는, MediaTracker 클래스에서 제공해 주는 클래스 변수와 주요 메소드는 다음과 같습니다.
l static int ABORTED: 미디어를 로딩(downloading)하는 것이 취소되었음(aborted)을 나타냅니다.
l static int COMPLETE: 미디어가 성공적으로 로딩 되었음을 나타냅니다.
l static int ERRORED: 미디어를 로딩(downloading)하는 중에 에러가 발생되었음을 나타냅니다.
l static int LOADING: 미디어가 현재 로딩중임을 나타냅니다.
l MediaTracker(Component comp): 주어진 컴포넌트에 대한 미디어 크랙커 객체를 생성합니다.
l void addImage(Image image, int id): 이미지 객체를 주어진 id로 미디어 트랙커에 추가합니다.
l void addImage(Image image, int id, int w, int h): 크기가 조절된 이미지(scaled image) 객체를 주어진 id로 미디어 트랙커에 추가합니다.
l boolean checkAll(): 등록된 모든 이미지가 모두 로딩되었는지를 얻습니다.
l boolean checkAll(boolean load): 등록된 모든 이미지가 모두 로딩되었는지를 얻습니다.
l boolean checkID(int id): 주어진 id로 등록된 모든 이미지가 로딩되었는지를 얻습니다.
l boolean checkID(int id, boolean load): 주어진 id로 등록된 모든 이미지가 로딩되었는지를 얻습니다.
l Object[] getErrorsAny(): 로딩 중에 에러가 발생한 모든 객체를 얻습니다.
l Object[] getErrorsID(int id): 로딩 중에 에러가 발생한 주어진 id를 갖는 모든 객체를 얻습니다.
l boolean isErrorAny(): 어떤 하나라도 에러가 있는지 모든 이미지 객체를 검사합니다.
l boolean isErrorID(int id): 어떤 하나라도 에러가 있는지 주어진 id의 모든 이미지 객체를 검사합니다.
l void removeImage(Image image): 주어진 이미지 객체를 이미지 트랙커에서 제거합니다.
l void removeImage(Image image, int id): 주어진 id를 갖는 모든 이미지 객체를 이미지 트랙커에서 제거합니다.
l void removeImage(Image image, int id, int width, int height): 주어진 조건의 이미지 객체를 이미지 트랙커에서 제거합니다.
l int statusAll(boolean load): 등록된 모든 이미지 객체가 갖는 상태에 대해 inclusive OR 비트 연산을 수행한 결과를 얻습니다.
l int statusID(int id, boolean load): 주어진 id로 등록된 모든 이미지 객체가 갖는 상태에 대해 inclusive OR 비트 연산을 수행한 결과를 얻습니다.
l void waitForAll(): 등록된 모든 이미지가 로딩될 때까지 기다립니다.
l boolean waitForAll(long ms): 등록된 모든 이미지가 로딩될 때까지 또는 주어진 시간이 종료될 때까지 기다립니다.
l void waitForID(int id): 주어진 id로 등록된 모든 이미지가 로딩될 때까지 기다립니다.
l boolean waitForID(int id, long ms): 주어진 id로 등록된 모든 이미지가 로딩될 때까지 또는 주어진 시간이 종료될 때까지 기다립니다.
자. 프린트(Print)
자바 프로그램에서 프린트 작업을 가능하게 하기 위하여, 자바 1.1에서는 자바 1.0에서 제공되던 기능을 개선하여 프린트하기 위한 표준 방법을 제공해 주고 있습니다. 이는 AWT(Abstract Window Toolkit) 컴포넌트를 이용하여 간단히 해결할 수 있습니다.
자바에서는 프린트 작업을 위해 PrintJob 추상클래스를 제공해 주고 있습니다. 추상 클래스는 프린트 작업(print job)을 초기화하고 실행합니다. 그리고 프린트 그래픽스 객체를 제공해 주고 있으며, PrintJob추상 클래스에서 프린트와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l abstract void end(): 프린트 작업을 마무리하고, 필요하다면 깨끗하게 지우는 작업을 수행합니다.
l void finalize(): 더 이상 참조되지 않으면 이 프린트 작업을 종료합니다.
l abstract Graphics getGraphics(): 프린트 그래픽스 객체를 얻습니다. 프린트 하고자 하는 내용을 이 객체를 이용하여 그려주면 됩니다.
l abstract Dimension getPageDimension(): 픽셀 단위의 페이지의 크기를 얻습니다.
l abstract int getPageResolution(): 페이지의 해상도(resolution)를 인치당 픽셀(pixels per inch) 크기로 얻습니다.
l abstract boolean lastPageFirst(): 마지막 페이지를 처음 프린트하도록 설정되어 있으면 true를 리턴합니다.
Component 클래스에서 프린트와 관련하여 제공해 주는 주요 메소드를 살펴보면 다음과 같습니다.
l void print(Graphics g): 이 컴포넌트를 프린트합니다.
l void printAll(Graphics g): 이 컴포넌트와 이 컴포넌트에 연결된 하위컴포넌트를 모두 프린트합니다.
프린트 작업을 하기 위한 PrintJob 객체를 얻기 위해 Toolkit 클래스에서 제공해 주는 다음과 같은 메소드를 이용할 수 있습니다.
l static Toolkit getDefaultToolkit(): 디폴트 툴킷을 얻습니다.
l abstract PrintJob getPrintJob(Frame frame, String jobtitle, Properties props): 툴킷 플랫폼 상에서 프린트 작업을 초기화하고 프린트 작업 객체(PrintJob object)를 얻습니다.
프린트 작업(print job)을 하기 위한 순서를 살펴보면, 다음과 같습니다.
l "Frame f = new Frame("test");": 프린트하기 위한 컴포넌트를 생성합니다.
l "PrintJob pj = f.getToolkit().getPrintJob(f, "print1", null);": 컴포넌트를 프린트하기 위한 PrintJob 객체를 얻습니다.
l "Graphics g = pj.getGraphics();": 프린트 그래픽스 객체를 얻습니다.
l "g.fillOval(5, 5, 150, 100);": 프린트 그래픽스 객체에 그리고자 하는 내용을 그립니다.
l "g.dispose();": 프린트 그래픽스 객체를 반환합니다.
l "pj.end();": 프린트 작업을 종료합니다.
다음에 나오는 자바 프로그램은 프린트 작업을 위한 간단한 예제를 보여 주고 있습니다.
import java.awt.*; import java.lang.*; class Print { public static void print(Frame f, Component c) { try { PrintJob pjob = f.getToolkit().getPrintJob(f, f.getTitle(), null); if(pjob == null) { System.out.println("pjob=null"); } else { Graphics pg = pjob.getGraphics(); if(pg == null) { System.out.println("printing, pjob=" + pg); } else { c.printAll(pg); pg.dispose(); // flush page } pjob.end(); } } catch(Exception e) { System.out.println("print error" + e); e.printStackTrace(); } } } class PrintCanvas extends Canvas { public void paint(Graphics g) { int x=20, y = 20; setBackground(Color.white); setForeground(Color.blue); g.drawLine(x, y, 99, 59); g.drawRect(x, y, 79, 39); g.drawRect(x+100, y, 79, 39); g.drawOval(x+100, y, 79, 39); g.drawRect(x+200, y, 79, 39); g.drawOval(x+200, y, 79, 39); } } class PrintTest extends Frame { public static void main(String[] args) { Frame f = new PrintTest(); f.setTitle("Print"); f.add(new PrintCanvas()); f.setSize(600, 700); f.setVisible(true); Print.print(f, f.getComponent(0)); } } /* * Results: D:\AIIT\JAVA\Working\08>java PrintTest D:\AIIT\JAVA\Working\08> */ |
<프로그램 32. PrintTest.java>
JDK 1.2의 프린팅 API를 이용하여 프린트 작업을 할 때, 제대로 동작은 하지만 작은 예제 임에도 불구하고 상당한 양의 프린트 파일이 나오며, 더군다나 UNIX에서는 수백 메가 바이트 정도가 됩니다. 이러한 문제 때문에, JDK 1.2 스윙 애플리케이션의 프린팅 수행능력을 향상시키기 위해서는, 스윙 컴포넌트를 출력할 때 디폴트로 사용하게 되어있는 더블 버퍼링(double buffering) 기능을 해제해 주어야 합니다.더블버퍼링 기능은 그래픽 표현 성능을 향상시켜 주지만, 프린트 작업을 할 경우에는 프린트 기능 향상을 위해 불필요한 작업을 추가적으로 해 주어야 합니다. 아래와 같이 RepaintManager 를 이용하여 더블 버퍼링 기능을 해제하면 됩니다.
RepaintManager.currentManager(this).setDoubleBufferingEnabled(false);
또한, UNIX의 PostScript 프린터에서 pixel을 읽고자 하는 경우에도 문제가 발생합니다. 실행시, 아래와 같이 java2d.font.usePlatformFont 을 옵션을 주어 해결할 수 있습니다.
java -Djava2d.font.usePlatformFont=true PrintBook
7. 자바 이벤트 모델
가. 자바 이벤트 처리 모델
자바 1.0 버전 이하에서 이벤트 처리 모델은 클래스 상속에 기반한 이벤트 모델로서 부모의 이벤트 핸들러를 상속 받는 것이 주된 골격이었습니다. 그러나 달라진 이벤트 처리 모델에서는 간단하고, 배우기 쉬우며, 어플리케이션 흐름과 GUI 처리 코드와의 보다 명확한 분리를 통해서 보다 안정된 이벤트 핸들링 코드를 제공하게 되는데 이러한 자바 1.1.x 이벤트 처리 모델을 위임형(delegation) 이벤트 처리 모델이라고 합니다. 우선 각 이벤트 종류는 java.util.EventObject클래스를 상속한 서브 클래스로 캡슐화 되어 있으며, 이러한 위임형 모델에서는 이벤트를 발생시키는 이벤트 소스(event source) 객체가 있고 이벤트가 발생했을 경우 이 이벤트 객체를 이벤트 리스너(event listener)로 전달하게 됩니다. 이 때, 이벤트 리스너는 전달되어 오는 이벤트를 기다렸다가 적당한 처리를 하게 되는 것입니다. 다음의 그림은 이러한 과정을 자세히 보여주고 있습니다.
<그림 6. 자바 이벤트 처리 모델>
이벤트 소스는 버튼(Button)이나 스크롤바(Scrollbar)와 같이 이벤트가 발생한 컴포넌트 객체를 말합니다. 각 컴포넌트에서 이벤트를 처리하기 위해, 다음과 같은 순서로 합니다.
l 먼저, 처리할 이벤트에 대한 이벤트 리스너를 작성합니다.
l 이벤트 리스너를 해당 컴포넌트에 등록합니다. 이 때, 하나의 이벤트 리스너는 두 개 이상의 컴포넌트에 등록될 수 있습니다. 예를 들어, "OK"와 "CANCEL" 두 개의 버튼이 있을 경우, 마우스 커서가 버튼 내로 들어오면 글씨의 색이 바뀌게 할 수 있습니다. 이러한 작업은 마우스 이벤트 리스너를 이용하여 가능하고, 두 버튼에 대해 같은 작업을 하게 되므로 같은 리스너를 두 버튼 모두에 등록하면 됩니다.
l 컴포넌트 객체에서 이벤트가 발생할 때 해당 컴포넌트는 이벤트 소스가 되고, 이 이벤트는 연결된 이벤트 리스너가 처리하도록 이벤트 리스너에게 전달됩니다.
l 이벤트 리스너는 전달받은 이벤트를 처리하게 됩니다.
나. 이벤트의 종류
모든 이벤트는 이벤트가 발생한 곳을 나타내는 컴포넌트 소스에 대한 참조값을 갖습니다. 그리고, EventObject 클래스에 의해 다음과 같은 기능이 제공됩니다.
l Object getSource(): 이벤트가 발생한 이벤트 소스 컴포넌트를 얻습니다.
AWTEvent 클래스는 모든 AWT 이벤트 클래스들에 대한 최상위 클래스라 할 수 있습니다. 그리고, AWTEvent 클래스와 AWTEvent 클래스의 하위클래스들은 java.awt.Event 클래스를 대신합니다. 그리고, AWTEvent 클래스에 정의되어 있는 이벤트 마스크는 등록된 리스너에 의해 선택되지 않은 이벤트 종류를 선택하기 위해 Component 클래스의 enableEvents 메소드를 사용하는 컴포넌트 클래스들에 의해 필요로 됩니다. 만약, 리스너가 컴포넌트에 등록된다면, 컴포넌트에 의해 적당한 이벤트 마스크가 내부적으로 설정됩니다. AWTEvent 클래스에서는 다음과 같은 이벤트 마스크와 주요 메소드를 제공해 주고있습니다.
l static long ACTION_EVENT_MASK
l static long ADJUSTMENT_EVENT_MASK:
l static long COMPONENT_EVENT_MASK
l static long CONTAINER_EVENT_MASK
l static long FOCUS_EVENT_MASK
l static long INPUT_METHOD_EVENT_MASK
l static long ITEM_EVENT_MASK
l static long KEY_EVENT_MASK
l static long MOUSE_EVENT_MASK
l static long MOUSE_MOTION_EVENT_MASK
l static long TEXT_EVENT_MASK
l static long WINDOW_EVENT_MASK
l static int RESERVED_ID_MAX: 예약된(reserved) AWT 이벤트 ID의 최대값
l int getID(): 이벤트의 종류를 얻습니다.
l String paramString(): 이벤트의 상태를 표현하는 문자열을 얻습니다.
자바에서 제공되는 이벤트 클래스들에 대한 클래스 계층도를 살펴보면, 다음의 그림과 같습니다.
<그림 7. 자바 이벤트 클래스 계층도>
다음은 이벤트 처리를 위해 Component 클래스에서 제공해 주는 메소드를 살펴보면, 다음과 같습니다.
l void addComponentListener(ComponentListener l): 컴포넌트 이벤트를 처리할 컴포넌트 리스너를 추가합니다.
l void addFocusListener(FocusListener l): 컴포넌트가 입력 포커스를 얻었을 때, 포커스 이벤트를 처리할 포커스 리스너를 추가합니다.
l void addInputMethodListener(InputMethodListener l): 입력 메소드 이벤트(input method event)를 처리할 입력 메소드 리스너를 추가합니다.
l void addKeyListener(KeyListener l): 키 이벤트를 처리할 키 리스너를 추가합니다.
l void addMouseListener(MouseListener l): 마우스 이벤트를 처리할 마우스 리스너를 추가합니다.
l void addMouseMotionListener(MouseMotionListener l): 마우스 동작(motion) 이벤트를 처리할 마우스 동작 리스너를 추가합니다.
l void deliverEvent(Event e): dispatchEvent(AWTEvent e) 메소드로 바뀌었습니다.
l void dispatchEvent(AWTEvent e): 이 컴포넌트 또는 하위컴포넌트에 이벤트를 발송합니다.
l String getName(): 컴포넌트의 이름을 얻습니다.
l Toolkit getToolkit(): Gets the toolkit of this component.
l boolean gotFocus(Event evt, Object what): processFocusEvent(FocusEvent) 메소드로 바뀌었습니다.
l boolean handleEvent(Event evt): processEvent(AWTEvent) 메소드로 바뀌었습니다.
l boolean hasFocus(): 컴포넌트가 키보드 포커스를 갖고 있는지를 얻습니다.
l boolean isFocusTraversable(): 탭(tab) 또는 쉬프트-탭(shift-tab ) 키를 사용하여 키보드 포커스를 이동할 수 있는지를 얻습니다.
l boolean keyDown(Event evt, int key): processKeyEvent(KeyEvent) 메소드로 바뀌었습니다.
l boolean keyUp(Event evt, int key): processKeyEvent(KeyEvent) 메소드로 바뀌었습니다.
l boolean lostFocus(Event evt, Object what): processFocusEvent(FocusEvent) 메소드로 바뀌었습니다.
l boolean mouseDown(Event evt, int x, int y): processMouseEvent(MouseEvent) 메소드로 바뀌었습니다.
l boolean mouseDrag(Event evt, int x, int y): processMouseMotionEvent(MouseEvent) 메소드로 바뀌었습니다.
l boolean mouseEnter(Event evt, int x, int y): processMouseEvent(MouseEvent) 메소드로 바뀌었습니다.
l boolean mouseExit(Event evt, int x, int y): processMouseEvent(MouseEvent) 메소드로 바뀌었습니다.
l boolean mouseMove(Event evt, int x, int y): processMouseMotionEvent(MouseEvent) 메소드로 바뀌었습니다.
l boolean mouseUp(Event evt, int x, int y): processMouseEvent(MouseEvent) 메소드로 바뀌었습니다.
l void nextFocus(): transferFocus() 메소드로 바뀌었습니다.
l boolean postEvent(Event e): dispatchEvent(AWTEvent) 메소드로 바뀌었습니다.
l protected void processEvent(AWTEvent e): 발생한 이벤트를 처리합니다.
l protected void processFocusEvent(FocusEvent e): 발생한 포커스 이벤트를 등록된 FocusListener 객체에 발송하여 처리하도록 합니다.
l protected void processInputMethodEvent(InputMethodEvent e): 발생한 입력 메소드 이벤트를 등록된 InputMethodListener 객체에 발송하여 처리하도록 합니다.
l protected void processKeyEvent(KeyEvent e): 발생한 입력 메소드 이벤트를 등록된 KeyListener 객체에 발송하여 처리하도록 합니다.
l protected void processMouseEvent(MouseEvent e) ): 발생한 입력 메소드 이벤트를 등록된 MouseListener 객체에 발송하여 처리하도록 합니다.
l protected void processMouseMotionEvent(MouseEvent e): 발생한 입력 메소드 이벤트를 등록된 MouseMotionListener 객체에 발송하여 처리하도록 합니다.
l void removeComponentListener(ComponentListener l): 주어진 컴포넌트 리스너를 제거합니다.
l void removeFocusListener(FocusListener l): 주어진 포커스 리스너를 제거합니다.
l void removeInputMethodListener(InputMethodListener l): 주어진 이벽 메소드 리스너를 제거합니다.
l void removeKeyListener(KeyListener l): 주어진 키 리스너를 제거합니다.
l void removeMouseListener(MouseListener l): 주어진 마우스 리스너를 제거합니다.
l void removeMouseMotionListener(MouseMotionListener l): 주어진 마우스 동작 리스너를 제거합니다.
l void requestFocus(): 입력 포커스를 얻도록 요청합니다.
l void transferFocus(): 다음 컴포넌트로 포커스를 전달합니다.
다음은 이벤트 처리를 위해 Container 클래스에서 제공해 주는 메소드를 살펴보면, 다음과 같습니다.
l void addContainerListener(ContainerListener l): 컨테이너 이벤트를 처리하기 위해 주어진 컨테이너 리스너(container listener)를 추가합니다.
l void deliverEvent(Event e): dispatchEvent(AWTEvent e) 메소드로 바뀌었습니다.
l protected void processContainerEvent(ContainerEvent e): 발생한 컨테이너 이벤트를 등록된 ContainerListener 객체에 발송하여 처리하도록 합니다.
l protected void processEvent(AWTEvent e): 이벤트를 처리합니다.
l void removeContainerListener(ContainerListener l): 컨테이너 리스너를 제거합니다.
다. 액션 이벤트(Action Event)
1 ) ActionEvent 클래스
컴포넌트가 정의하고 있는 액션이 발생했다는 것을 가리키는 이벤트로서 실제 이벤트가 아닌 의미상의 이벤트입니다. 예를 들어, 버튼 컴포넌트에서 버튼이 눌렸을 때, 이러한 고수준의 액션 이벤트가 발생합니다. 이러한 액션 이벤트는 컴포넌트에 따라 각각 정의되어 있습니다. 컴포넌트의 addActionListener 메소드를 이용하여 액션 이벤트를 처리할 ActionListener 객체를 등록할 수 있고, 이렇게 등록된 모든ActionListener 객체에 액션 이벤트가 전달되어 처리되도록 합니다. 이 때, ActionListener 객체는 ActionListener 인터페이스를 구현한 것입니다. AWTEvent 클래스가 제공해 주는 기능을 살펴보면, 다음과 같습니다.
l static int ACTION_FIRST: 액션 이벤트를 위해 사용되는 id의 범위를 나타내는 첫 번째 수
l static int ACTION_LAST: 액션 이벤트를 위해 사용되는 id의 범위를 나타내는 마지막 수
l static int ACTION_PERFORMED: 의미있는 액션이 발생했다는 것을 나타내는 이벤트 id
l static int ALT_MASK: alt modifier
l static int CTRL_MASK: control modifier
l static int META_MASK: meta modifier
l static int SHIFT_MASK: shift modifier
l String getActionCommand(): 액션과 관련된 명령어 문자열을 얻습니다.
l int getModifiers(): 액션이 발생할 때 함께 눌린 modifier 키를 얻습니다.
l String paramString(): 액션 이벤트를 가리키는 파라메터 문자열을 얻습니다.
2 ) ActionListener 인터페이스
ActionListener 인터페이스는 액션 이벤트를 받아서 처리할 리스너가 구현해야할 기능을 정의하고 있는 인터페이스입니다. 따라서, 액션 이베트를 처리할 클래스는 이 인터페이스를 구현해야 하고, 객체를생성한 후 액션 이벤트를 처리할 컴포넌트의 addActionListener 메소드를 이용하여 컴포넌트에 등록하게 됩니다. 액션이 발생했을 경우, 해당 액션 리스너의 다음과 같은 actionPerformed 메소드가 내부적으로호출됩니다.
l void actionPerformed(ActionEvent e): 액션이 발생할 때 호출됩니다.
다음에 나오는 자바 프로그램은 ActionEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; class ActionEventTest extends Frame { Button b1, b2, b3; public ActionEventTest() { setLayout(new FlowLayout()); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } }); ActionListener wa = new ActionListener() { public void actionPerformed(ActionEvent e) { if(e.getSource() == b1) { b1.setEnabled(false); b2.setEnabled(true); b3.setForeground(Color.blue); } else if(e.getActionCommand().equals("Disable")) { b1.setEnabled(true); b2.setEnabled(false); b3.setForeground(Color.black); } } }; b1 = new Button("Enable"); b2 = new Button("Disable"); b2.setEnabled(false); b3 = new Button("Tester"); b1.addActionListener(wa); b2.addActionListener(wa); add(b1); add(b2); add(b3); } public static void main(String args[]) { ActionEventTest f = new ActionEventTest(); f.pack(); // setSize(200, 60); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java ActionEventTest D:\AIIT\JAVA\08> */ |
<프로그램 33. ActionEventTest.java>
라. 조정 이벤트(Adjustment Event)
1 ) AdjustmentEvent 클래스
조정 이벤트(AdjustmentEvent)는 Adjustable 인터페이스를 구현하는 컴포넌트에서 값을 변경하려고 시도할 때 발생하는 이벤트입니다. Adjustable 인터페이스를 구현하는 대표적인 컴포넌트는 스크롤바(Scrollbar) 컴포넌트입니다. 사용자가 스크롤바 컴포넌트의 값을 변경할 때, 스크롤바 컴포넌트는 AdjustmentEvent 객체를 받습니다. 이 때, 스크롤바 컴포넌트가 먼저 이 이벤트를 처리하고, 등록된 리스너에게 해당 이벤트를 전달합니다. 예를 들어, 사용자가 마우스를 이용하여 스크롤바 컴포넌트의 값을 바꾸거나 키보드에서 PGUP, PGDN 등의 키를 치면, 조정 이벤트가 발생합니다. AdjustmentEvent 클래스가 제공해 주는 기능을 살펴보면, 다음과 같습니다.
l static int ADJUSTMENT_FIRST: 조정 이벤트 id의 처음 값
l static int ADJUSTMENT_LAST: 조정 이벤트 id의 마지막 값
l static int ADJUSTMENT_VALUE_CHANGED: 이벤트 값
l static int BLOCK_DECREMENT: 수평 스크롤바 컴포넌트의 버블 오른쪽 트랙 또는 수직 스크롤바 컴포넌트의 버블 아래쪽 트랙 내에서 마우스로 클랙했거나 PGDN 키가 눌렸을 때 발생합니다.
l static int BLOCK_INCREMENT: 수평 스크롤바 컴포넌트의 버블 왼쪽 트랙 또는 수직 스크롤바 컴포넌트의 버블 위쪽 트랙 내에서 마우스로 클랙했거나 PGUP 키가 눌렸을 때 발생합니다.
l static int TRACK: 스크롤바 컴포넌트의 버블(bubble)을 마우스로 드래그할 때 발생합니다.
l static int UNIT_DECREMENT: 수평 스크롤바 컴포넌트의 오른쪽 화살표 버튼 또는 수직 스크롤바 컴포넌트의 아래 화살표 버튼을 눌렀을 경우나 해당 키가 눌렸을 때 발생합니다.
l static int UNIT_INCREMENT: 수평 스크롤바 컴포넌트의 왼쪽 화살표 버튼 또는 수직 스크롤바 컴포넌트의 위 화살표 버튼을 눌렀을 경우나 해당 키가 눌렸을 때 발생합니다.
l Adjustable getAdjustable(): 이벤트가 발생한 Adjustable 객체를 얻습니다.
l int getAdjustmentType(): 값이 바뀌도록 하는 이벤트를 발생시킨 조정의 종류(type of adjustment)를 얻습니다.
l int getValue(): 조정 이벤트 내의 현재 값을 얻습니다.
다음에 나오는 그림은 스크롤바 컴포넌트와 조정 이벤트와의 관계를 보여주고 있습니다.
<그림 8. 스크롤바 컴포넌트와 조정 이벤트와의 괸계>
2 ) AdjustmentListener 인터페이스
AdjustmentListener 인터페이스는 조정 이벤트(adjustment event)를 받아서 처리할 리스너가 구현해야할 기능을 정의하고 있는 인터페이스입니다. 따라서, 조정 이베트를 처리할 클래스는 이 인터페이스를 구현해야 합니다. 다시 말해서, 다음과 같은 adjustmentValueChanged 메소드를 구현해 주어야 합니다.
l void adjustmentValueChanged(AdjustmentEvent e): 조정값(value of the adjustable)이 변할 때 호출됩니다.
l 조정 리스너를 구현하였다면, 스크롤바 컴포넌트에 등록해 주기 위해 Scrollbar 클래스에서 제공해주는 다음과 같은 메소드를 사용하면 됩니다.
l void addAdjustmentListener(AdjustmentListener l): 조정 이벤트를 처리할 조정 리스너를 추가합니다.
l void removeAdjustmentListener(AdjustmentListener l): 주어진 조정 리스너를 제거합니다.
다음에 나오는 자바 프로그램은 AdjustmentEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; class AdjustmentEventTest extends Frame { Scrollbar slider; public AdjustmentEventTest() { setLayout(new FlowLayout()); slider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 10, 0, 100); slider.setSize(200, 40); add(slider); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); slider.addAdjustmentListener(new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent e) { System.out.println(e.paramString()+", "+e.getAdjustmentType()+", } }); } public static void main(String args[]) { AdjustmentEventTest f = new AdjustmentEventTest(); f.pack(); f.setVisible(true); f.setTitle("AdjustmentEvent"); } } /* * Results: D:\AIIT\JAVA\08>java AdjustmentEventTest ADJUSTMENT_VALUE_CHANGED,adjType=BLOCK_INCREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=UNIT_INCREMENT,value=11, 1, 11 ADJUSTMENT_VALUE_CHANGED,adjType=UNIT_DECREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=BLOCK_DECREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=TRACK,value=9, 5, 9 ADJUSTMENT_VALUE_CHANGED,adjType=TRACK,value=18, 5, 18 ADJUSTMENT_VALUE_CHANGED,adjType=UNIT_INCREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=UNIT_DECREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=BLOCK_DECREMENT, ADJUSTMENT_VALUE_CHANGED,adjType=BLOCK_INCREMENT, D:\AIIT\JAVA\08> */ |
<프로그램 34. AdjustmentEventTest.java>
마. 컴포넌트 이벤트(Component Event)
1 ) ComponentEvent 클래스
컴포넌트가 이동되었거나, 크기가 변경되었나, 또는 보이고 안보이도록 설정될 때 발생하는 저수준 이벤트입니다. 컴포넌트 이벤트는 단지 알려주기 위한 목적으로 사용되고, AWT에서는 컴포넌트의 크기 변경 및 이동에 대해 내부적으로 자동으로 처리하고, 프로그램에서 이 이벤트를 처리하든 하지않았든지에 상관없이 레이아웃을 수행하도록 하기 위해 사용됩니다. 또한, InputEvent, FocusEvent, WindowEvent, ContainerEvent 등과 같은 컴포넌트 관련 이벤트의 상위클래스로 사용됩니다. 컴포넌트 이벤트는 컴포넌트에 등록된 모든 컴포넌트 리스너에게 전달되어 처리되고, 이 때 컴포넌트 리스너는Component 클래스의 addComponentListener 메소드에 의해 컴포넌트에 등록할 수 있습니다. ComponentEvent 클래스에 의해 제공되는 기능은 다음과 같습니다.
l static int COMPONENT_FIRST: 컴포넌트 이벤트 id의 시작 번호
l static int COMPONENT_LAST: 컴포넌트 이벤트 id의 마지막 번호
l static int COMPONENT_MOVED: 컴포넌트의 위치가 변경되었음을 나타냅니다.
l static int COMPONENT_RESIZED: 컴포넌트의 크기가 변경되었음을 나타냅니다.
l static int COMPONENT_SHOWN: 컴포넌트가 보여지도록 설정되었다는 것을 나타냅니다.
l static int COMPONENT_HIDDEN: 컴포넌트가 보이지 않도록 설정되었다는 것을 나타냅니다.
l Component getComponent(): 이벤트가 발생한 컴포넌트를 얻습니다.
l String paramString(): 이벤트를 유일하게 나타내는 파라메터 문자열을 얻습니다.
2 ) ComponentListener 인터페이스
ComponentListener 인터페이스는 컴포넌트 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 컴포넌트 이벤트를 처리하고자 하는 클래스는 이러한 ComponentListener 인터페이스가 정의하고 있는 모든 메소드를 구현하거나, 또는 추상 클래스인 ComponentAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. ComponentListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void componentHidden(ComponentEvent e): 컴포넌트가 안보이도록 설정될 때 호출됩니다.
l void componentMoved(ComponentEvent e): 컴포넌트의 위치가 변경되었을 때 호출됩니다.
l void componentResized(ComponentEvent e): 컴포넌트의 크기가 변경되었을 때 호출됩니다.
l void componentShown(ComponentEvent e): 컴포넌트가 보이도록 설정될 때 호출됩니다.
3 ) ComponentAdapter 클래스
컴포넌트 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. ComponentAdapter 클래스는 ComponentListener 인터페이스가 정의하고 있는 메소드를 구현하고있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 ComponentAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. ComponentAdapter 클래스에 의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void componentHidden(ComponentEvent e): 컴포넌트가 안보이도록 설정될 때 호출됩니다.
l void componentMoved(ComponentEvent e): 컴포넌트의 위치가 변경되었을 때 호출됩니다.
l void componentResized(ComponentEvent e): 컴포넌트의 크기가 변경되었을 때 호출됩니다.
l void componentShown(ComponentEvent e): 컴포넌트가 보이도록 설정될 때 호출됩니다.
다음에 나오는 자바 프로그램은 ComponentEvent 를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; public class ComponentEventTest extends Frame { public ComponentEventTest() { super("ComponentEvent"); ComponentListener cl = new ComponentAdapter() { public void componentHidden(ComponentEvent e) { System.out.println(e); } public void componentMoved(ComponentEvent e) { System.out.println(e); } public void componentResized(ComponentEvent e) { System.out.println(e); } public void componentShown(ComponentEvent e) { System.out.println(e); } }; addComponentListener(cl); Button b = new Button("Button"); add(b); b.addComponentListener(cl); b.setSize(100, 50); b.setName("OK"); b.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); } public static void main(String[] args) { ComponentEventTest f = new ComponentEventTest(); f.setSize(200, 100); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java ComponentEventTest java.awt.event.ComponentEvent[COMPONENT_RESIZED (4,23 192x73)] on OK java.awt.event.ComponentEvent[COMPONENT_MOVED (4,23 192x73)] on OK java.awt.event.ComponentEvent[COMPONENT_SHOWN] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (2,0 200x100)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (2,0 177x80)] on frame0 java.awt.event.ComponentEvent[COMPONENT_RESIZED (4,23 169x53)] on OK java.awt.event.ComponentEvent[COMPONENT_MOVED (8,1 177x80)] on frame0 java.awt.event.ComponentEvent[COMPONENT_MOVED (42,21 177x80)] on frame0 D:\AIIT\JAVA\08> */ |
<프로그램 35. ComponentEventTest.java>
위의 자바 프로그램을 실행시킨 후, 윈도우의 위치를 변화시키거나 크기를 변경시키면, 해당 프레임 컴포넌트와 버튼 컴포넌트에 컴포넌트 이벤트가 발생합니다. 물론, 두 개의 컴포넌트는 같은 행동을 하는 컴포넌트 리스너를 가지고 있습니다. 이 때, 윈도우(프레임)의 크기를 변화시킬 때는 두 개의 컴포넌트 모두 COMPONENT_RESIZED 이벤트가 발생하고, 크기를 변경시킬 때는 프레임 컴포넌트에 대해서는 COMPONENT_MOVED 이벤트가 발생하는 것이 주의하셔야 합니다. 다시 말해서, 버튼 컴포넌트의 위치는 프레임 컴포넌트 내에서 그대로이기 때문입니다. 물론, 크기는 프레임 컴포넌트의 크기 변화에 따라 버튼 컴포넌트도 변합니다.
바. 컨테이너 이벤트(Container Event)
1 ) ContainerEvent 클래스
컨테이너 컴포넌트에 컴포넌트를 추가하거나 제거할 때, 컨테이너의 내용이 바뀌었음을 나타내는 저수준 이벤트입니다. 컨테이너 이벤트는 단지 알려주기 위한 목적으로 사용되고, AWT에서는 컨테이너컴포넌트에 컴포넌트가 추가/제거될 때 내부적으로 자동으로 처리하고, 프로그램에서 이 이벤트를 처리하든 하지않았든지에 상관없이 레이아웃을 수행하도록 하기 위해 사용됩니다. 컨테이너 이벤트는컨테이너 컴포넌트에 등록된 모든 컨테이너 리스너에게 전달되어 처리되고, 이 때 컨테이너 리스너는 Container 클래스의 addContainerListener 메소드에 의해 컨테이너 컴포넌트에 등록할 수 있습니다. ContainerEvent 클래스에 의해 제공되는 기능은 다음과 같습니다.
l static int COMPONENT_ADDED: 컴포넌트가 추가되었음을 나타냅니다.
l static int COMPONENT_REMOVED: 컴포넌트가 제거되었음을 나타냅니다.
l static int CONTAINER_FIRST: 컨테이너 이벤트 id의 시작 번호입니다.
l static int CONTAINER_LAST: 컨테이너 이벤트 id의 마지막 번호입니다.
l Component getChild(): 이벤트에 의해 영향을 받는 컴포넌트를 얻습니다.
l Container getContainer(): 이벤트가 발생한 컨테이너 컴포넌트를 얻습니다.
2 ) ContainerListener 인터페이스
ContainerListener 인터페이스는 컨테이너 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 컨테이너 이벤트를 처리하고자 하는 클래스는 이러한 ContainerListener 인터페이스가 정의하고있는 모든 메소드를 구현하거나, 또는 추상 클래스인 ContainerAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. ContainerListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과같습니다.
l void componentAdded(ContainerEvent e): 어떤 컴포넌트가 컨테이너 컴포넌트에 추가될 때 호출됩니다.
l void componentRemoved(ContainerEvent e): 어떤 컴포넌트가 컨테이너 컴포넌트에서 제거될 때 호출됩니다.
3 ) ContainerAdapter 클래스
컨테이너 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. ContainerAdapter 클래스는 ContainerListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 ContainerAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. ContainerAdapter 클래스에 의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void componentAdded(ContainerEvent e): 어떤 컴포넌트가 컨테이너 컴포넌트에 추가될 때 호출됩니다.
l void componentRemoved(ContainerEvent e): 어떤 컴포넌트가 컨테이너 컴포넌트에서 제거될 때 호출됩니다.
다음에 나오는 자바 프로그램은 ContainerEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; public class ContainerEventTest extends Frame { Button b1, b2, b3; public ContainerEventTest() { setLayout(new FlowLayout()); addContainerListener(new ContainerAdapter() { public void componentAdded(ContainerEvent e) { System.out.println(e); } public void componentRemoved(ContainerEvent e) { System.out.println(e); } }); b1 = new Button("Add"); b2 = new Button("Remove"); b3 = new Button("Exit"); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { if(e.getSource() == b1) { if(b3.getParent() != ContainerEventTest.this) { add(b3); } } else if(e.getActionCommand().equals("Remove")) { if(b3.isVisible()) { remove(b3); } } ContainerEventTest.this.pack(); } }; b1.addActionListener(al); b2.addActionListener(al); b3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { removeAll(); System.exit(0); } }); add(b1); add(b2); add(b3); } public static void main(String[] args) { ContainerEventTest f = new ContainerEventTest(); f.setTitle("ContainerEvent"); f.pack(); // f.setSize(200, 60); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java ContainerEventTest java.awt.event.ContainerEvent[COMPONENT_ADDED,child=button0] on frame0 java.awt.event.ContainerEvent[COMPONENT_ADDED,child=button1] on frame0 java.awt.event.ContainerEvent[COMPONENT_ADDED,child=button2] on frame0 java.awt.event.ContainerEvent[COMPONENT_REMOVED,child=button2] java.awt.event.ContainerEvent[COMPONENT_ADDED,child=button2] on frame0 java.awt.event.ContainerEvent[COMPONENT_REMOVED,child=button2] java.awt.event.ContainerEvent[COMPONENT_REMOVED,child=button1] java.awt.event.ContainerEvent[COMPONENT_REMOVED,child=button0] D:\AIIT\JAVA\08> */ |
<프로그램 36. ContainerEventTest.java>
위의 프로그램을 실행시킨 후, “Remove” 버튼을 누르면, “Ecit” 버튼이 프레임으로부터 제거되고, “Add” 버튼을 누르면 다시 프레임 컴포넌트에 추가되며, “Exit” 버튼을 누르면 프레임 컴포넌트가 포함하고있는 모든 컴포넌트들을 종료시킨 후, 프로그램을 종료합니다.
사. 포커스 이벤트(Focus Event)
1 ) FocusEvent 클래스
컴포넌트가 키보드 포커스를 얻거나 잃을 때 발생하는 저수준 이벤트입니다. 이러한 포커스 이벤트는 텍스트 필드 컴포넌트와 같은 컴포넌트에서 주로 발생합니다. 이 이벤트는 FocusListener 또는FocusAdapter 객체에 전달되고, Component 클래스의 addFocusListener 메소드를 이용하여 등록할 수 있습니다.
이 때, 포커스의 변화는 다음과 같은 두 가지 수준이 있습니다.
l 순간적인(temporary) 포커스 변화: requestFocus 메소드 호출 또는 사용자가 탭 키를 이용하여 컴포넌트 간에 포커스를 이동시킬 때 발생하는 포커스 변화 이벤트 입니다.
l 영원한(permanent) 포커스 변화: 윈도우의 비활성화 또는 스크롤 바의 드래그와 같은 다른 동작에 의한 간접적인 결과로서 포커스를 순간적으로 얻거나 잃을 때 발생하는 포커스 변화 이벤트입니다. 이런 경우, 윈도우가 다시 활성화되거나 해당 동작이 끝나면 포커스는 자동으로 전 상태로 복구됩니다.
위의 두 가지 포커스 이벤트 모두 FOCUS_GAINED와 FOCUS_LOST 이벤트 id를 발생시키고, 이 때 isTemporary 메소드를 이용하여 포커스 이벤트의 종류를 얻을 수 있습니다. 이러한 FocusEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static int FOCUS_FIRST: 포커스 이벤트 id의 시작 번호입니다.
l static int FOCUS_LAST: 포커스 이벤트 id의 마지막 번호입니다.
l static int FOCUS_GAINED: 포커스를 얻었음을 나타냅니다.
l static int FOCUS_LOST: 포커스를 잃었음을 나타냅니다.
l boolean isTemporary(): 포커스 변화 이벤트가 순간적인지 영원한지를 얻습니다.
2 ) FocusListener 인터페이스
FocusListener 인터페이스는 포커스 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 포커스 이벤트를 처리하고자 하는 클래스는 이러한 FocusListener 인터페이스가 정의하고 있는 모든메소드를 구현하거나, 또는 추상 클래스인 FocusAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. FocusListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void focusGained(FocusEvent e): 컴포넌트가 키보드 포커스를 얻었을 때 호출됩니다.
l void focusLost(FocusEvent e): 컴포넌트가 키보드 포커스를 잃었을 때 호출됩니다.
3 ) FocusAdapter 클래스
컨테이너 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. FocusAdapter 클래스는 FocusListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 FocusAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. FocusAdapter 클래스에의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void focusGained(FocusEvent e): 컴포넌트가 키보드 포커스를 얻었을 때 호출됩니다.
l void focusLost(FocusEvent e): 컴포넌트가 키보드 포커스를 잃었을 때 호출됩니다.
다음에 나오는 자바 프로그램은 FocusEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; public class FocusEventTest extends Frame { Button b1; TextField tf; TextArea ta; public FocusEventTest() { b1 = new Button("Ok"); tf = new TextField(20); ta = new TextArea(2, 20); add("North", tf); add("Center", ta); add("South", b1); FocusListener fl = new FocusAdapter() { public void focusGained(FocusEvent e) { System.out.println(e); } public void focusLost(FocusEvent e) { System.out.println(e); } }; b1.addFocusListener(fl); tf.addFocusListener(fl); tf.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { ta.requestFocus(); } }); ta.addFocusListener(fl); b1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); setVisible(true); pack(); b1.requestFocus(); } public static void main(String[] args) { FocusEventTest f = new FocusEventTest(); f.setTitle("FocusEvent"); } } /* * Results: D:\AIIT\JAVA\08>java FocusEventTest java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on button0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on button0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on text0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on text0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on textfield0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on text0 java.awt.event.FocusEvent[FOCUS_LOST,temporary] on text0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on text0 java.awt.event.FocusEvent[FOCUS_LOST,permanent] on text0 java.awt.event.FocusEvent[FOCUS_GAINED,permanent] on button0 D:\AIIT\JAVA\08> */ |
<프로그램 37. FocusEventTest.java>
위의 자바 프로그램을 실행시킨 후, 버튼 컴포넌트가 제일 먼저 포커스를 얻습니다. 그리고, 마우스로 텍스트 필드 컴포넌트를 클릭하면, 버튼 컴포넌트는 포커스를 잃고 텍스트 필드 컴포넌트가 포커스를얻습니다. 다음으로, 텍스트(“FocusEventTest”)를 입력하고 엔터키 또는 탭 키를 치게되면, 텍스트 필드 컴포넌트에 대한 액션 이벤트가 발생하고, 이 때 텍스트 필드 컴포넌트의 액션 리스너에 의해 포커스는 텍스트 영역 컴포넌트로 이동하게 됩니다. 물론, 버튼 컴포넌트가 포커스를 가지고 있는 상태에서 엔터키를 치면 버튼 컴포넌트에 대한 액션 이벤트가 발생합니다.
아. 입력 이벤트(Input Event)
1 ) InputEvent 클래스
InputEvent 클래스는 모든 컴포넌트 수준 입력 이벤트를 위한 최상위 이벤트 클래스입니다. 입력 이벤트는 이벤트가 발생한 이벤트 소스 컴포넌트에 의해 처리되기 전에 리스너에 전달됩니다. 이러한 방식은 리스너와 컴포넌트의 하위클래스들이 이 이벤트를 사용하도록 하고, 이벤트 소스 컴포넌트의 디폴트 방법으로 처리하지 않도록 합니다. 예를 들어, mousePressed 이벤트가 발생했을 경우 버튼 컴포넌트에서 mousePressed 이벤트를 사용해버린다면, 버튼 컴포넌트가 활성화 되지 못하게 됩니다. 따라서, 이벤트 소스 컴포넌트에 의해 해당 이벤트가 처리되기 전에 이벤트 리스너에게 전달됩니다. InputEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static int ALT_GRAPH_MASK
l static int ALT_MASK
l static int BUTTON1_MASK
l static int BUTTON2_MASK
l static int BUTTON3_MASK
l static int CTRL_MASK
l static int META_MASK
l static int SHIFT_MASK
l void consume(): 이벤트가 발생한 이벤트 소스 컴포넌트에 의해 디폴트 방법으로 처리되지 않도록 하기 위해 이벤트를 소비하여 없애버립니다
l int getModifiers(): modifiers 플래그를 얻습니다.
l long getWhen(): 이벤트가 발생한 타임스탬프를 얻습니다.
l boolean isAltDown(): Alt modifier가 눌렸는지를 얻습니다.
l boolean isAltGraphDown(): Alt-Graph modifier가 눌렸는지를 얻습니다.
l boolean isConsumed(): 이벤트가 소비되었는지를 얻습니다.
l boolean isControlDown(): Control modifier가 눌렸는지를 얻습니다.
l boolean isMetaDown(): Meta modifier가 눌렸는지를 얻습니다.
l boolean isShiftDown(): Shift modifier가 눌렸는지를 얻습니다.
자. 키 이벤트(Key Event)
1 ) KeyEvent 클래스
KeyEvent 클래스는 InputEvent 클래스의 하위클래스로서 컴포넌트 내에서 발생한 키의 입력을 위한 기능을 제공해 주는 이벤트 클래스입니다. 이 이벤트는 텍스트 필드 컴포넌트와 같은 컴포넌트에서 발생할 수 있는 저수준 이벤트로서, 키가 눌리거나(pressed), 다시 놓이거나(released) 또는 타이프(pressed and released) 되었을 때 각각 이벤트가 발생합니다. 이 이벤트는 Component 클래스의 addKeyListener 메소드에 의해 키 이벤트를 처리하기 위해 등록된 KeyListener 또는 KeyAdapter 객체에 전달됩니다.
"Key typed" 이벤트는 고수준 이벤트로서 플랫폼이나 키보드 레이아웃에 독립적입니다. 이 이벤트는 문자가 입력되었을 때 발생하는 이벤트로서 입력된 문자를 정확하게 알 수 있는 방법을 제공해 주고 있습니다.
가장 간단한 경우, "key typed" 이벤트는 키의 눌림(pressed)과 놓임(released) 이벤트의 조합으로 만들어집니다. 또는 키를 께속 누르고 있을 경우에도 연속적인 "key typed" 이벤트가 발생합니다. 그러나, F1과같은 액션키 또는 Shift 키와 같은 modifier 키들에 대해서는 "Key typed" 이벤트가 발생하지 않습니다. 그리고, getKeyChar 메소드는 항상 키에 해당하는 유니코드 또는 CHAR_UNDEFINED를 리턴해 줍니다. 키가 눌리거나 놓일 경우에는 getKeyCode 메소드는 키의 코드값을 리턴하고, 키가 타이프 도었을 경우에는 항상 VK_UNDEFINED를 리턴합니다. "key pressed"와 "key released" 이벤트는 저수준 이벤트로서 플랫폼과 키보드 레이아웃에 의존합니다. 이 이벤트는 키가 눌리거나 놓일 때마다 생성되고, 문자 입력이 발생하지 않는 F1 키와 같은 액션 키와 Shift 키와 같은 modifier 키가 눌렸는지를 알 수 있는 방법입니다. getKeyCode 메소드를 이용하여 해당 키에 대한 가상 키 코드를 알 수 있습니다. 예를 들어, Shift 키를 눌렀을 때 VK_SHIFT 코드를 갖는 KEY_PRESSED 이벤트가 발생하고, 반면 'a' 가 눌릴 때 VK_A 코드를 갖는 KEY_PRESSED 이벤트가 발생하고, 'a' 키를 놓으면 VK_A 코드를 갖는 KEY_RELEASED 이벤트가 발생합니다. 물론, 이 때 KEY_TYPED 이벤트가 발생하고 그 때의 키문자는 'A가 됩니다.
F1 키와 같이 문자로 나타나지 않는 키는 KEY_TYPED 이벤트를 발생시키지 못합니다. 또한, 모든 키보드 또는 시스템에서 모든 가상 키 코드를 생성할 수 있는 것은 아닙니다. 그렇다고 자바에서 이러한키를 인공적으로 생성하려고 하지는 않습니다. 가상 키(Virtual key) 코드는 플랫폼과 키보드 레이아웃에 의존하는 물리적인 키를 구분하지 않습니다. 예를 들어, 미국판 윈도우의 키보드 레이아웃은VK_O를 나타내는데, 프랑스판 윈도우의 키보드 레이아웃에서는 VK_A를 나타냅니다. 액션 키를 플랫폼 독립적으로 지원하기 위해서, 자바 플랫폼은 몇 개의 추가적인 가상 키를 위한 상수를 사용함으로써, 그렇지 않을 경우 가상 키 코드와 modifier들을 해석하여 입력된 키를 인식해야만 하는 번거로움을 제거해주고 있습니다. 예를 들어, 일본판 윈도우에서 ALT modifer 와 함께 VK_CONVERT 키 대신VK_ALL_CANDIDATES 키가 얻어집니다. 이 때, 한 가지 주의할 점은 VK_ENTER, VK_BACK_SPACE, 그리고 VK_TAB 등과 같이 자바 언어에 의해 정의되어 있는 키를 제외하고는 VK_ 상수의 값에 의존하지 말아야 합니다. KeyEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static char CHAR_UNDEFINED: 유효하지 못한 유니코드 문자입니다.
l static int KEY_FIRST: 키 이벤트 id의 시작 번호입니다.
l static int KEY_LAST: 키 이벤트 id의 마지막 번호입니다.
l static int KEY_PRESSED: "key pressed" 이벤트가 발생했음을 나타냅니다.
l static int KEY_RELEASED: "key released" 이벤트가 발생했음을 나타냅니다.
l static int KEY_TYPED: "key typed" 이벤트가 발생했음을 나타냅니다.
l static int VK_: 가상 키코드 상수
l char getKeyChar(): 이벤트 내의 키와 관련된 문자를 얻습니다.
l int getKeyCode(): 이벤트 내의 키와 관련된 정수 키코드를 얻습니다.
l static String getKeyModifiersText(int modifiers): "Shift" 또는 "Ctrl+Shift" 와 같은 문자열을 얻습니다.
l static String getKeyText(int keyCode): "HOME", "F1" 또는 "A"와 같은 문자열을 얻습니다.
l boolean isActionKey(): 이벤트 내의 키가 액션 키인지를 얻습니다.
l String paramString(): 이벤트를 구분할 수 있는 파라메터 문자열을 얻습니다.
l void setKeyChar(char keyChar): 논리적인 문자(logical character)를 나타내기 위한 keyChar 값을 얻습니다.
l void setKeyCode(int keyCode): 물리적인 키(physical key)를 가리키기 위한 keyCode 값을 설정합니다.
l void setModifiers(int modifiers): shift, ctrl, alt, 그리고 meta 등과 같은 추가적인 키를 나타내는 modifier를 설정합니다.
2 ) KeyListener 인터페이스
KeyListener 인터페이스는 키 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 키 이벤트를 처리하고자 하는 클래스는 이러한 KeyListener 인터페이스가 정의하고 있는 모든 메소드를 구현하거나, 또는 추상 클래스인 KeyAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. KeyListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void keyPressed(KeyEvent e): 키가 눌렸을 때 호출됩니다.
l void keyReleased(KeyEvent e): 키가 놓였을 때 호출됩니다.
l void keyTyped(KeyEvent e): 키가 타이프 되었을 때 호출됩니다.
3 ) KeyAdapter 클래스
키 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. KeyAdapter 클래스는 KeyListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 KeyAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. KeyAdapter 클래스에 의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void keyPressed(KeyEvent e): 키가 눌렸을 때 호출됩니다.
l void keyReleased(KeyEvent e): 키가 놓였을 때 호출됩니다.
l void keyTyped(KeyEvent e): 키가 타이프 되었을 때 호출됩니다.
다음에 나오는 자바 프로그램은 KeyEvent 를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; import java.awt.event.KeyEvent; class KeyEventTest extends Frame{ int posX = 0, posY = 0; String inputString = ""; KeyEventTest() { final TextField input = new TextField() { public Dimension getPreferredSize() { return new Dimension(0,0); } }; final Canvas display = new Canvas() { public void update(Graphics g) { paint(g); } public void paint(Graphics g) { g.drawString(inputString, posX, posY ); } }; display.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { inputString = ""; posX = e.getX(); posY = e.getY(); input.requestFocus(); // 포커스를 TextField로 전송 } }); display.addFocusListener(new FocusAdapter() { public void focusGained(FocusEvent e) { input.requestFocus(); // 포커스를 TextField로 전송 } }); input.addKeyListener(new KeyAdapter() { public void keyTyped(KeyEvent e) { inputString += e.getKeyChar(); // 네이티브 입력기로부터의 한글이 전달된다. display.repaint(); } }); add(display, "Center" ); add(input, "West" ); } public static void main(String[] args) { KeyEventTest f = new KeyEventTest(); f.setSize(160, 100); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java KeyEventTest D:\AIIT\JAVA\08> */ |
<프로그램 38. KeyEventTest.java>
자바에서는 키보드, 마우스 등의 입력장치로부터 발생하는 입력 등과 같은 각 이벤트에 대해서 클래스로 정의하고 있고, 이러한 이벤트가 발생했을 경우 이를 처리하기 위한 각 이벤트 리스너(listener)를 인터페이스로 정의하고 있습니다. 이 중 키가 눌리고 놓이거나 또는 키가 타이프 되는 등의 키보드 이벤트를 처리하기 위한 메소드를 정의하고 있는 KeyListener 인터페이스와 이 KeyListener 인터페이스를 구현해 놓은 KeyAdapter 클래스가 있습니다. 따라서, 자바 프로그래머는 이러한 Adapter가 제공해 주는 메소드를 재정의함으로써 이벤트 처리를 할 수 있습니다. 키보드에서 엔터 키가 눌렸을 때, 특정 버튼이수행되도록 하려면, KeyAdapter 클래스 객체의 해당 메소드를 재정의하고, 이 KeyAdapter 객체를 해당 버튼의 키 리스너로 등록하면 됩니다. 다음은 간단한 자바 예제 프로그램입니다.
import java.awt.*; import java.awt.event.*; class KeyEventTest2 extends Frame { public KeyEventTest2() { Button b = new Button("EnterButton"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); b.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { System.out.println("keyChar: " + e.getKeyChar() + ", keyCode: " + e.getKeyCode() + "(" + KeyEvent.getKeyText(e.getKeyCode()) + "), modifiers: " + e.getModifiers() + "(" + KeyEvent.getKeyModifiersText(e.getModifiers()) + "), actionKey: " + e.isActionKey()); } }); add(b); } public static void main(String[] args) { KeyEventTest2 f = new KeyEventTest2(); f.setSize(150, 60); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>javac KeyEventTest2.java D:\AIIT\JAVA\08>java KeyEventTest2 keyChar: , keyCode: 10(Enter), modifiers: 0(), actionKey: false keyChar: l, keyCode: 76(L), modifiers: 0(), actionKey: false keyChar: k, keyCode: 75(K), modifiers: 0(), actionKey: false keyChar: ?, keyCode: 16(Shift), modifiers: 1(Shift), actionKey: false keyChar: A, keyCode: 65(A), modifiers: 1(Shift), actionKey: false keyChar: a, keyCode: 65(A), modifiers: 0(), actionKey: false keyChar: ?, keyCode: 120(F9), modifiers: 0(), actionKey: true keyChar: ?, keyCode: 121(F10), modifiers: 0(), actionKey: true keyChar: 3, keyCode: 51(3), modifiers: 0(), actionKey: false D:\AIIT\JAVA\08> */ |
<프로그램 39. KeyEventTest.java>
차. 마우스 이벤트(Mouse Event)
1 ) MouseEvent 클래스
마우스 이벤트는 두 가지로 나뉩니다. 먼저, click, enter, 그리고 exit 등과 같은 이벤트를 갖는 마우스 이벤트(mouse event)와 moves와 drag 등을 갖는 마우스 동작 이벤트(mouse motion event)가 있습니다.
MouseEvent 객체는 Component 클래스의 addMouseListener 메소드를 이용하여 마우스 이벤트를 처리하기 위해 등록된 MouseListener 또는 MouseAdapter 객체에게 전달됩니다. 또한, MouseEvent 객체는Component 클래스의 addMouseMotionListener 메소드를 이용하여 마우스 동작 이벤트를 처리하기 위해 등록된 MouseMotionListener 또는 MouseMotionAdapter 객체에게 전달됩니다. 마우스 버튼이 클릭되었을 때,이벤트가 생성되고, modifier 필드에 버튼 마스크가 저장되어 등록되어 있는 MouseListeners 객체에 보내집니다. MouseEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static int MOUSE_FIRST: 마우스 이벤트 id의 시작 번호입니다.
l static int MOUSE_LAST: 마우스 이벤트 id의 마지막 번호입니다.
l static int MOUSE_PRESSED: 마우스의 버튼이 눌렸음을 나타냅니다.
l static int MOUSE_RELEASED: 마우스의 버튼이 놓였음을 나타냅니다.
l static int MOUSE_CLICKED: 마우스의 버튼이 클릭되었음을 나타냅니다.
l static int MOUSE_ENTERED: 마우스가 컴포넌트의 영역 내로 들어왔음을 나타냅니다.
l static int MOUSE_EXITED: 마우스가 컴포넌트의 영역 밖으로 나갔음을 나타냅니다.
l static int MOUSE_MOVED: 마우스가 움직였음을 나타냅니다.
l static int MOUSE_DRAGGED: 마우스가 드래그되었음을 나타냅니다.
l int getClickCount(): 마우스가 클릭된 수를 얻습니다.
l Point getPoint(): 이벤트 소스 컴포넌트에 상대적인 마우스 커서의 좌표를 얻습니다.
l int getX(): 이벤트 소스 컴포넌트에 상대적인 마우스 커서의 x 좌표를 얻습니다.
l int getY(): 이벤트 소스 컴포넌트에 상대적인 마우스 커서의 y 좌표를 얻습니다.
l boolean isPopupTrigger(): 마우스 이벤트가 플랫폼을 위한 팝업 메뉴를 나타나게할 이벤트인지를 얻습니다.
l void translatePoint(int x, int y): 이벤트가 발생한 좌표를 현재의 좌표의 수평 위치에 x값만큼을 수직 위치에 y값만큼을 더한 새로운 위치로 옮깁니다.
2 ) MouseListener 인터페이스
MouseListener 인터페이스는 마우스 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 마우스 이벤트를 처리하고자 하는 클래스는 이러한 MouseListener 인터페이스가 정의하고 있는 모든메소드를 구현하거나, 또는 추상 클래스인 MouseAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. MouseListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void mouseClicked(MouseEvent e): 컴포넌트 상에서 마우스가 클릭되었을 때 호출됩니다.
l void mouseEntered(MouseEvent e): 마우스가 컴포넌트 영역 안으로 들어왔을 때 호출됩니다.
l void mouseExited(MouseEvent e): 마우스가 컴포넌트 영역 밖으로 나갈 때 호출됩니다.
l void mousePressed(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 눌릴 때 호출됩니다.
l void mouseReleased(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 놓일 때 호출됩니다.
3 ) MouseAdapter 클래스
마우스 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. MouseAdapter 클래스는 MouseListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 MouseAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. MouseAdapter 클래스에의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void mouseClicked(MouseEvent e): 컴포넌트 상에서 마우스가 클릭되었을 때 호출됩니다.
l void mouseEntered(MouseEvent e): 마우스가 컴포넌트 영역 안으로 들어왔을 때 호출됩니다.
l void mouseExited(MouseEvent e): 마우스가 컴포넌트 영역 밖으로 나갈 때 호출됩니다.
l void mousePressed(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 눌릴 때 호출됩니다.
l void mouseReleased(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 놓일 때 호출됩니다.
4 ) MouseMotionListener 인터페이스
MouseMotionListener 인터페이스는 마우스 동작 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 마우스 동작 이벤트를 처리하고자 하는 클래스는 이러한 MouseMotionListener 인터페이스가 정의하고 있는 모든 메소드를 구현하거나, 또는 추상 클래스인 MouseMotionAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. MouseMotionListener 인터페이스에 의해 정의되어 있는 메소드를살펴보면, 다음과 같습니다.
l void mouseDragged(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 눌려진 상태로 드래그 될 때 호출됩니다.
l void mouseMoved(MouseEvent e): 컴포넌트 상에서 마우스가 움직일 때 호출됩니다.
5 ) MouseMotionAdapter 클래스
마우스 동작 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. MouseMotionAdapter 클래스는 MouseMotionListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만, 실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 MouseMotionAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. MouseMotionAdapter 클래스에 의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void mouseDragged(MouseEvent e): 컴포넌트 상에서 마우스의 버튼이 눌려진 상태로 드래그 될 때 호출됩니다.
l void mouseMoved(MouseEvent e): 컴포넌트 상에서 마우스가 움직일 때 호출됩니다.
6 ) Pop-up 메뉴 만들기
자바 AWT 프로그램을 작성하다보면, 마우스의 오른쪽 버튼을 눌렀을 때 현재 마우스의 커서 위치에 팝업 메뉴를 나타내주는 기능을 추가하고자 하는 경우가 많습니다. 자바 프로그램에서 마우스의 버튼이 눌렸을 때 눌린 버튼이 왼쪽, 가운데, 또는 오른쪽 버튼인 지를 알아내기 위해서는 AWT에서 제공해 주고 있는 이벤트 중에서 InputEvent 및 MouseEvent 클래스의 객체 정보를 이용해야 합니다. 다음은 질문과 관련되어 사용가능한 InputEvent 및 MouseEvent 클래스의 주요 메소드를 요약한 것입니다.
<표 1> MouseEvent 클래스와 InputEvent 클래스의 주요 메소드
Public class MouseEvent extends InputEvent | ||
GetX() | 마우스 이벤트가 발생했을 때의 X 좌표값 | |
GetY() | 마우스 이벤트가 발생했을 때의 Y 좌표값 | |
GetPoint() | 마우스 이벤트가 발생했을 때의 (X,Y) 좌표값에 대한 Point 객체 | |
GetClickCount() | 마우스 이벤트가 발생했을 때의 마우스 클릭 횟수 | |
Public abstract class InputEvent extends ComponentEvent | ||
SHIFT_MASK | 0x01 (00000001) | SHIFT 키에 대한 마스크 상수값 |
CTRL_MASK | 0x02 (00000010) | CTRL 키에 대한 마스크 상수값 |
META_MASK | 0x04 (00000100) | META 키에 대한 마스크 상수값 |
ALT_MASK | 0x08 (00001000) | ALT 키에 대한 마스크 상수값 |
BUTTON1_MASK | 0x10 (00010000) | 마우스의 왼쪽 버튼에 대한 마스크 상수값 |
BUTTON2_MASK | 0x08=ALT_MASK | 마우스의 가운데 버튼에 대한 마스크 상수값 |
BUTTON3_MASK | 0x04=META_MASK | 마우스의 오른쪽 버튼에 대한 마스크 상수값 |
GetModifiers() | 키보드 또는 마우슨 이벤트 발생 시의 modifier 플래그를 얻음 | |
IsControlDown() | CTRL 키가 눌렸는 지의 여부 | |
IsShiftDown() | SHIFT 키가 눌렸는 지의 여부 | |
IsAltDown() | ALT 키 또는 마우스의 가운데 버튼이 눌렸는 지의 여부 | |
IsMetaDown() | META 키 또는 마우스의 오른쪽 버튼이 |
<표 2>에서는 마우스의 클릭 이벤트가 발생했을 경우, SHIFT, CTRL, ALT 등의 키와 마우스의 왼쪽, 오른쪽 버튼이 눌릴 경우 modifiers 플래그의 값과 해당 문자열을 보여줍니다. 이 때, 플래그 값은 InputEvent클래스의 getModifiers 메소드를 이용하여 얻을 수 있고, 문자열은 KeyEvent 클래스의 getKeyModifiersText(e.getModifiers()) 메소드를 이용하여 구할 수 있습니다.
<표 2> Modifiers 플래그 상태표
키 | 마우스 버튼 | Modifiers | ||||
CTRL | ALT | SHIFT | Left | Right | 플래그 | 문자열 |
| | | O | | 16 | |
O | | | O | | 18 | Ctrl |
| O | | O | | 24 | Alt |
| | O | O | | 17 | Shift |
O | O | | O | | 26 | Ctrl+Alt |
O | | O | O | | 19 | Ctrl+Shift |
| O | O | O | | 25 | Alt+Shift |
O | O | O | O | | 27 | Ctrl+Alt+Shift |
| | | | O | 4 | Meta |
O | | | | O | 6 | Meta+Ctrl |
| O | | | O | 12 | Meta+Alt |
| | O | | O | 5 | Meta+Shift |
O | O | | | O | 14 | Meta+Ctrl+Alt |
O | | O | | O | 7 | Meta+Ctrl+Shift |
| O | O | | O | 13 | Meta+Alt+Shift |
O | O | O | | O | 15 | Meta+Ctrl+Alt+Shift |
단, 위의 값들은 MouseAdapter의 mousePressed 메소드 내에서의 결과임 |
다음에 나오는 자바 프로그램은 마우스의 오른쪽 버튼이 눌렸는지를 체크하여, 마우스가 눌린 위치에 팝업 메뉴를 보여주기 위한 예제 프로그램입니다.
import java.awt.*; import java.awt.event.*; public class PopupMenuMouseEventTest extends Frame { public PopupMenuMouseEventTest() { final PopupMenu popupMenu = new PopupMenu("Popup"); popupMenu.add(new MenuItem("Undo")); MenuItem redoMenu = new MenuItem("Redo"); redoMenu.setEnabled(false); popupMenu.add(redoMenu); popupMenu.addSeparator(); Menu editMenu = new Menu("Edit"); editMenu.add(new MenuItem("Cut")); editMenu.add(new MenuItem("Copy")); MenuItem pasteMenu = new MenuItem("Paste"); pasteMenu.setEnabled(false); editMenu.add(pasteMenu); popupMenu.add(editMenu); popupMenu.addSeparator(); MenuItem quit = new MenuItem("Quit"); popupMenu.add(quit); quit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); add(popupMenu); addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { if(e.getModifiers() == InputEvent.META_MASK) { popupMenu.show(e.getComponent(), e.getX(), e.getY()); } System.out.println("Mouse Event: " + "XY(" + e.getX() + "," + e.getY() + "), " + "Modifiers: " + e.getModifiers() + ":" + KeyEvent.getKeyModifiersText(e.getModifiers()) + ", " } }); } public static void main(String args[]) { PopupMenuMouseEventTest f = new PopupMenuMouseEventTest(); f.setTitle("PopupMenu&MouseEvent"); f.setSize(300, 200); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java PopupMenuMouseEventTest Mouse Event: XY(135,79), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(58,58), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(25,42), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(150,55), Modifiers: 16:, clickCount: 1 Mouse Event: XY(116,51), Modifiers: 16:, clickCount: 1 Mouse Event: XY(67,54), Modifiers: 16:, clickCount: 1 Mouse Event: XY(57,55), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(34,34), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(29,64), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(19,25), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(26,31), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(26,24), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(14,25), Modifiers: 4:Meta, clickCount: 1 Mouse Event: XY(33,32), Modifiers: 4:Meta, clickCount: 1 D:\AIIT\JAVA\08> */ |
<프로그램 40. PopupMenuMouseEventTest.java>
위의 자바 프로그램에서 팝업 메뉴를 사용하기 위해서, 먼저 PopupMenu 객체를 생성하고, 팝업 메뉴에 들어갈 각 MenuItem 객체 또는 Menu 객체를 생성하여 팝업 메뉴 객체에 추가시켜 주면 됩니다. 이 때팝업 메뉴에 등록된 메뉴 중 하나가 선택되면 ActionEvent가 발생하므로, 각 MenuItem 객체가 선택되었을 경우 해야 할 작업을 지정하기 위해서는 ActionListener를 구현하여 각 MenuItem 객체에 추가해 주면됩니다. 그리고, 위에서 설명한데로 마우스의 오른쪽 버튼이 눌렸을 경우, 해당 위치에 팝업 메뉴를 보여주고 있습니다.
카. 아이템 이벤트(Item Event)
1 ) ItemEvent 클래스
아이템이 선택되고 선택 해제된 것을 나타내는 의미적인 이벤트입니다. List 컴포넌트와 같은 ItemSelectable 객체에 의해 생성되는 고수준 이벤트로서, ItemSelectable 객체가 포함하고 있는 아이템이 선택되거나 선택해제되었을 경우 발생합니다. 이 이벤트는 Component 클래스의 addItemListener 메소드를 이용하여 아이템 이벤트를 처리하기 위하여 등록된 모든 ItemListener 객체에 전달됩니다. 이 때, 리스너는마우스가 움직이고 클릭되는 등과 같은 개개의 이벤트에 대해 알 필요는 없고, 단지 아이템이 선택되고 선택해제되는 등의 의미있는 이벤트만 가지면 됩니다. ItemEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static int ITEM_FIRST: 아이템 이벤트 id의 시작 번호를 나타냅니다.
l static int ITEM_LAST: 아이템 이벤트 id의 마지막 번호를 나타냅니다.
l static int SELECTED: 선택 해제된 아이템이 선택될 경우의 상태변화를 나타냅니다.
l static int DESELECTED: 선택된 아이템이 선택 해제가 될 경우의 상태변화를 나타냅니다.
l static int ITEM_STATE_CHANGED: 아이템의 상태가 변했음을 나타냅니다.
l Object getItem(): 이벤트가 발생한 아이템 객체를 얻습니다.
l ItemSelectable getItemSelectable(): 이벤트가 발생한 소스 컴포넌트를 얻습니다.
l int getStateChange(): 상태 변화의 종류를 얻습니다.
ItemSelectable 인터페이스는 위와 같이 선택가능한 아이템을 가질 수 있는 컴포넌트을 위한 기능을 정의하고 있습니다. 이러한 ItemSelectable 인터페이스를 구현하고 있는 컴포넌트는 다음과 같습니다.
l Checkbox
l CheckboxMenuItem
l Choice
l List
ItemSelectable 인터페이스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l void addItemListener(ItemListener l): 아이템 리스너를 추가합니다.
l void removeItemListener(ItemListener l): 주어진 아이템 리스너를 삭제합니다.
2 ) ItemListener 인터페이스
ItemListener 인터페이스는 아이템 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 아이템 이벤트를 처리하고자 하는 클래스는 이러한 ItemListener 인터페이스가 정의하고 있는 모든 메소드를 구현해야 합니다. ItemListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void itemStateChanged(ItemEvent e): 아이템의 상태가 변했을 때 호출됩니다.
다음에 나오는 자바 프로그램은 ItemEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; class ItemEventTest extends Frame { MenuBar menuBar; Menu viewMenu; List win32; Choice unix; public ItemEventTest() { setLayout(new FlowLayout()); ItemListener il = new ItemListener() { public void itemStateChanged(ItemEvent e) { System.out.println(e); } }; menuBar = new MenuBar(); setMenuBar(menuBar); viewMenu = new Menu("View"); menuBar.add(viewMenu); CheckboxMenuItem cmi1 = new CheckboxMenuItem("Toolbar"); CheckboxMenuItem cmi2 = new CheckboxMenuItem("StatusBar"); viewMenu.add(cmi1); viewMenu.add(cmi2); cmi1.addItemListener(il); cmi2.addItemListener(il); win32 = new List(3, true); win32.add("Winodws 95"); win32.add("Winodws 98"); win32.add("Winodws NT"); win32.addItemListener(il); setLayout(new FlowLayout()); unix = new Choice(); unix.add("Solaris"); unix.add("Linux"); unix.add("BSD"); unix.add("Mach"); unix.addItemListener(il); add(win32); add(unix); } public static void main(String args[]) { ItemEventTest f = new ItemEventTest(); f.setTitle("ItemEvent"); f.pack(); f.setVisible(true); f.setLocation(100, 100); } } /* * Results: D:\AIIT\JAVA\08>java ItemEventTest java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= java.awt.event.ItemEvent[ITEM_STATE_CHANGED,item= D:\AIIT\JAVA\08> */ |
<프로그램 41. ItemEventTest.java>
타. 텍스트 이벤트(Component Event)
1 ) TextEvent 클래스
객체의 텍스트가 변한 것을 나타내는 의미적인 이벤트입니다. TextComponent 컴포넌트와 같은 객체에 의해 생성되는 고수준 이벤트로서, 객체가 포함하고 있는 텍스트 변경되었을 경우 발생합니다. 이 이벤트는 TextComponent 클래스의 addTextListener 메소드를 이용하여 텍스트 이벤트를 처리하기 위하여 등록된 모든 TextListener 객체에 전달됩니다. 이 때, 리스너는 마우스가 움직이고 키가 눌리는 등과 같은개개의 이벤트에 대해 알 필요는 없고, 단지 텍스트가 변했다는 의미있는 이벤트만 가지면 됩니다. TextEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과 같습니다.
l static int TEXT_FIRST: 텍스트 이벤트 id의 시작 번호입니다.
l static int TEXT_LAST: 텍스트 이벤트 id의 마지막 번호입니다.
l static int TEXT_VALUE_CHANGED: 텍스트가 변했음을 나타냅니다.
2 ) TextListener 인터페이스
TextListener 인터페이스는 텍스트 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 텍스트 이벤트를 처리하고자 하는 클래스는 이러한 TextListener 인터페이스가 정의하고 있는 모든 메소드를 구현해야 합니다. TextListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void textValueChanged(TextEvent e): 텍스트의 내용이 변했을 때 호출됩니다.
다음에 나오는 자바 프로그램은 TextEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; class TextEventTest extends Frame { Button b1; TextField tf; TextArea ta; EventQueue eventQ; public TextEventTest() { b1 = new Button("Close"); tf = new TextField(20); ta = new TextArea(2, 20); eventQ = Toolkit.getDefaultToolkit().getSystemEventQueue(); add("North", tf); add("Center", ta); add("South", b1); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.out.println(ta.getText()); System.exit(0); } }); FocusListener fl = new FocusAdapter() { public void focusGained(FocusEvent e) { tf.requestFocus(); } }; tf.addFocusListener(fl); ta.addFocusListener(fl); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { ta.append(tf.getText()+"\n"); tf.setText(""); if(e.getSource() == b1) { eventQ.postEvent(new WindowEvent((Frame)b1.getParent(), } } }; tf.addActionListener(al); b1.addActionListener(al); TextListener tl = new TextListener() { public void textValueChanged(TextEvent e) { System.out.println(e); } }; tf.addTextListener(tl); ta.addTextListener(tl); tf.requestFocus(); } public static void main(String args[]) { TextEventTest f = new TextEventTest(); f.setLocation(100, 100); f.setTitle("TextEvent"); f.setVisible(true); f.pack(); } } /* * Results: D:\AIIT\JAVA\08>java TextEventTest java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on text0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on text0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on text0 java.awt.event.TextEvent[TEXT_VALUE_CHANGED] on textfield0 캬 컥 ! D:\AIIT\JAVA\08> */ |
<프로그램 42. TextEventTest.java>
파. 윈도우 이벤트(Window Event)
1 ) WindowEvent 클래스
윈도우의 상태가 변한 것을 나타내는 저수준 이벤트입니다. 윈도우가 열리거나, 닫히거나, 닫히는 중이거나, 활성화/비활성화 되었거, 아이콘화/정상화 되었을 경우 Window 객체에 의해 발생되는 저수준이벤트입니다. 이 이벤트는 Window 클래스의 addWindowListener 메소드를 이용하여 텍스트 이벤트를 처리하기 위하여 등록된 모든 WindowListener 또는 WindowAdapter 객체에 전달됩니다. 이 때, 리스너는 마우스가 움직이고 키가 눌리는 등과 같은 개개의 이벤트에 대해 알 필요는 없고, 단지 텍스트가 변했다는 의미있는 이벤트만 가지면 됩니다. WindowEvent 클래스에 의해 제공되는 기능을 살펴보면, 다음과같습니다.
l static int WINDOW_ACTIVATED: 윈도우가 활성화되었음을 나타냅니다.
l static int WINDOW_CLOSED: 윈도우가 닫혔음을 나타냅니다.
l static int WINDOW_CLOSING: 윈도우가 닫히고 있음을 나타냅니다.
l static int WINDOW_DEACTIVATED: 윈도우가 비활성화되었음을 나타냅니다.
l static int WINDOW_DEICONIFIED: 윈도우가 정상화되었음을 나타냅니다.
l static int WINDOW_FIRST: 윈도우 이벤트 id의 시작 번호입니다.
l static int WINDOW_ICONIFIED: 윈도우가 아이콘화되었음을 나타냅니다.
l static int WINDOW_LAST: 윈도우 이벤트 id의 마지막 번호입니다.
l static int WINDOW_OPENED: 윈도우가 열렸음을 나타냅니다.
l Window getWindow(): 이벤트가 발생한 이벤트 소스 컴포넌트를 얻습니다.
2 ) WindowListener 인터페이스
WindowListener 인터페이스는 윈도우 이벤트를 처리할 수 있는 기능을 정의하고 있는 인터페이스입니다. 윈도우 이벤트를 처리하고자 하는 클래스는 이러한 WindowListener 인터페이스가 정의하고 있는 모든 메소드를 구현하거나, 또는 추상 클래스인 WindowAdapter 클래스의 관련 메소드를 재정의하여 확장해야 합니다. WindowListener 인터페이스에 의해 정의되어 있는 메소드를 살펴보면, 다음과 같습니다.
l void windowActivated(WindowEvent e): 윈도우가 활성화되었을 때 호출됩니다.
l void windowClosed(WindowEvent e): 윈도우가 닫혔을 때 호출됩니다.
l void windowClosing(WindowEvent e): 윈도우가 닫히고 있을 때 호출됩니다.
l void windowDeactivated(WindowEvent e): 윈도우가 비활성화되었을 때 호출됩니다.
l void windowDeiconified(WindowEvent e): 윈도우가 정상화되었을 때 호출됩니다.
l void windowIconified(WindowEvent e): 윈도우가 아이콘화되었을 때 호출됩니다.
l void windowOpened(WindowEvent e): 윈도우가 열렸을 때 호출됩니다.
3 ) WindowAdapter 클래스
윈도우 이벤트를 받아서 처리하기 위한 추상 어댑터 클래스(abstract adapter class)를 제공해 주고 있습니다. WindowAdapter 클래스는 WindowListener 인터페이스가 정의하고 있는 메소드를 구현하고 있지만,실제 메소드의 몸체 부분은 비어 있습니다. 따라서, 자바 프로그램 개발자는 WindowAdapter 클래스의 메소드 중 자신이 처리하고자 하는 이벤트를 위한 메소드를 재정의 해주면 됩니다. WindowAdapter 클래스에 의해 제공되는 메소드를 살펴보면, 다음과 같습니다.
l void windowActivated(WindowEvent e): 윈도우가 활성화되었을 때 호출됩니다.
l void windowClosed(WindowEvent e): 윈도우가 닫혔을 때 호출됩니다.
l void windowClosing(WindowEvent e): 윈도우가 닫히고 있을 때 호출됩니다.
l void windowDeactivated(WindowEvent e): 윈도우가 비활성화되었을 때 호출됩니다.
l void windowDeiconified(WindowEvent e): 윈도우가 정상화되었을 때 호출됩니다.
l void windowIconified(WindowEvent e): 윈도우가 아이콘화되었을 때 호출됩니다.
l void windowOpened(WindowEvent e): 윈도우가 열렸을 때 호출됩니다.
다음에 나오는 자바 프로그램은 WindowEvent를 사용하는 예를 보여주는 프로그램입니다.
import java.awt.*; import java.awt.event.*; public class WindowEventTest extends Frame { public WindowEventTest() { super("WindowEvent"); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } public void windowActivated(WindowEvent e) { System.out.println(e); } public void windowClosed(WindowEvent e) { System.out.println(e); } public void windowDeactivated(WindowEvent e) { System.out.println(e); } public void windowDeiconified(WindowEvent e) { System.out.println(e); } public void windowIconified(WindowEvent e) { System.out.println(e); } public void windowOpened(WindowEvent e) { System.out.println(e.paramString()); } }); } public static void main(String[] args) { WindowEventTest w = new WindowEventTest(); w.setSize(400, 200); w.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java WindowEventTest java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 WINDOW_OPENED java.awt.event.WindowEvent[WINDOW_DEACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_DEACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_ICONIFIED] on frame0 java.awt.event.WindowEvent[WINDOW_DEACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 java.awt.event.WindowEvent[WINDOW_DEICONIFIED] on frame0 java.awt.event.WindowEvent[WINDOW_ACTIVATED] on frame0 D:\AIIT\JAVA\08> */ |
<프로그램 43. WindowEventTest.java>
하. 이벤트 큐(Event Queue)
모든 이벤트는 발생하는 즉시 시스템의 이벤트 큐에 저장되고, 순서대로 하나씩 처리됩니다. 이러한 시스템 이벤트 큐 객체를 알아내는 방법은, 다음 예제 프로그램을 살펴보면 쉽게 알 수 있습니다. 다음예제는 사용자가 프레임을 마우스로 닫거나, 혹은, 1초(1000밀리초) 경과 후에 프로그램에 의해 발생된 이벤트에 의해 프로그램의 실행이 종료됩니다. 종료되는 이유는 윈도우 이벤트 처리부분에서“System.exit(0);” 문을 수행하기 때문이며, 이벤트가 발생한다고 해서 종료되는 것은 절대 아닙니다. 하나의 어플리케이션이 여러 개의 프레임을 가지는 경우, 하나의 프레임만을 닫는다고 해서 프로그램을무조건 종료 시키는 것은 아닙니다. 즉, 해당 프레임만 제거하고 싶은 경우가 있을 것입니다. 이런 경우, 예제에 나와 있듯이, dispose() 메소드를 호출해 주면 된다.
import java.awt.*; import java.awt.event.*; class EventQueueTest extends Frame { Window w; Button b1, b2; EventQueue eventQ; public EventQueueTest() { final Button b3 = new Button("Close"); final Button b4 = new Button("Exit"); setLayout(new FlowLayout()); eventQ = Toolkit.getDefaultToolkit().getSystemEventQueue(); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.out.println(e);; System.exit(0); } }); b1 = new Button("Show"); b1.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { b1.setEnabled(false); b2.setEnabled(true); w.setVisible(true); System.out.println(e);; } }); b1.setEnabled(true); b2 = new Button("Hide"); b2.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { b1.setEnabled(true); b2.setEnabled(false); w.setVisible(false); System.out.println(e);; } }); b2.setEnabled(false); add(b1); add(b2); w = new Window(this); w.setLayout(new FlowLayout()); w.add(b3); w.add(b4); b3.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { b1.setEnabled(true); b2.setEnabled(false); w.dispose(); System.out.println(e);; } }); b4.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { eventQ.postEvent(new WindowEvent(w.getOwner(), System.out.println(e);; } }); w.setLocation(150,84); w.pack(); b1.setName("Show"); b2.setName("Hide"); b3.setName("Close"); b4.setName("Exit"); } public static void main(String args[]) { EventQueueTest f = new EventQueueTest(); f.setTitle("EventQueue"); f.setLocation(50, 70); f.pack(); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java EventQueueTest java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Show] on Show java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Hide] on Hide java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Show] on Show java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Close] on Close java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Show] on Show java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Exit] on Exit java.awt.event.WindowEvent[WINDOW_CLOSING] on frame0 D:\AIIT\JAVA\08> */ |
<프로그램 44. EventQueueTest.java>
가. 메뉴단축키와 이벤트 처리
JDK 1.1에서는 메뉴에 대한 단축키를 지정할 수 있도록 해 주었습니다. 따라서, 마우스로 메뉴를 선택하는 대신, 키보드를 이용하여 메뉴를 선택할 수 있습니다. 다음에 나오는 자바프로그램은 메뉴를 생성하고, 단축키를 이용하여 메뉴를 실행하기 위한 간단한 예제입니다.
import java.awt.*; import java.awt.event.*; public class MenuShortcutEventTest extends Frame { public MenuShortcutEventTest() { MenuBar menuBar = new MenuBar(); Menu fileMenu = new Menu("File"); menuBar.add(fileMenu); ActionListener al = new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println(e); if(((MenuItem)e.getSource()).getLabel().equals("Exit")) { System.exit(0); } } }; MenuItem newItem = MenuItem openItem = MenuItem saveItem = MenuItem exitItem = newItem.addActionListener(al); openItem.addActionListener(al); saveItem.addActionListener(al); exitItem.addActionListener(al); fileMenu.add( newItem); fileMenu.add(openItem); fileMenu.add(saveItem); fileMenu.add(exitItem); setMenuBar(menuBar); } public static void main(String args[]) { MenuShortcutEventTest f = new MenuShortcutEventTest(); f.setTitle("MenuShortcutEvent"); f.setSize(320, 200); f.setVisible(true); } } /* * Results: D:\AIIT\JAVA\08>java MenuShortcutEventTest java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=New] on menuitem0 java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Open] on menuitem1 java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Save] on menuitem2 java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Open] on menuitem1 java.awt.event.ActionEvent[ACTION_PERFORMED,cmd=Exit] on menuitem3 D:\AIIT\JAVA\08> */ |
<프로그램 45. MenuShortcutEventTest.java>