PROGRAMMER CHALLENGE

Java SE 2004/01/06 14:21 Posted by Sun

이번 테크팁은 프로그래머에게 한단계 높은 수준의 과제를 던져준다. 이 과제는 2003년도와 그 이전에 소개된 몇 가지 팁을 통해 풀 수 있다. 2003년의 테크팁이 Java 3D와 JMX APIs 다루기에서 동적 클래스 언로딩에 이르기까지 Java platform spectrum의 여러 방면에 걸쳐 많은 주제를 다루었다면, 이번 테크팁의 주제는 완전하지는 않지만, PhotoShop과 유사한 간단한 그리기 프로그램을 생성하는 데에 필요한 과정에 초점이 맞춰져 있다.

그렇다면 그리기 프로그램에서 필요한 기능들을 먼저 알아보자. 첫번째로, 그래픽 애플리케이션(graphical application)을 위한 프레임이 하나 필요하다. 2003/12/8 스윙에서의 멀티스레딩에서 언급했듯이, 이 프레임은 메인 프로그램의 쓰레드가 아닌 이벤트 쓰레드에서 보여져야 한다. 이 글을 읽는 독자 중에는 java.awt.Window 의 show 메소드가 deprecated인지 궁금해 하는 사람도 있겠지만 그렇진 않다. 대신에 java.awt.Component 의 show 메소드가 deprecated이다.

두번째로 꼭 필요하지는 않지만 메뉴 라벨에 사용할 텍스트 스트링을 리소스 번들에 위치시킬 것을 권장한다.(1998/5/21 리소스 번들 사용하기사용하기 참조) 사실 여러 가지 언어로 번들을 제공할 필요는 없지만 프로그램이 각 지역에서 불편없이 작동하게 하려면 번들 내에 적어도 꼭 필요한 스트링을 넣어 두는 것이 좋은 방법이다.

그리기 프로그램은 다음과 같은 메뉴를 갖고 각각의 메뉴에서 지정하는 액션을 지원해야 한다.

File Menu:
  New (clear the image)
  Save (save the image)
  Exit (exit the application)

Edit Menu:
  Clear (clear a selected area)
  Rotate (rotate a selected area)
  Horizontal Flip (flip the selected area horizontally)
  Vertical Flip (flip the selected area vertically)

Attributes Menu:
  Background (select the background when clearing the screen)
  Foreground (select the foreground for the drawing color)
  Stroke Size (select the width of the drawing line)

Toolbar (Drawing Modes):
  Normal (draw as the mouse moves)
  Draw Line (draw a line)
  Draw Rect (draw a rectangle)
  Fill Rect (draw a filled rectangle)
  Draw Oval (draw an oval)
  Fill Oval (draw a filled oval)
  Select Area (select an area to perform an operation from the Edit menu)

툴바 동작(operation)은 상호배타적(mutually exclusive)이기 때문에 애플리케이션 사용자는 한번에 한가지 동작만을 실행할 수 있다.

애플리케이션의 사용자 환경은 다음과 같다.

DrawJGUI

좀 더 그래픽을 강화한 사용자 환경을 원한다면 툴바에 서로 다른 동작에 해당하는 아이콘을 넣어줄 수가 있다. 썬은 Java look and feel Graphics Repository에서 아이콘 세트를 제공하고 있다.

이 과제의 솔루션은 3개의 클래스로 이루어져 있다. 하나는 GUI를 나타내고, 두번째는 사이즈가 640 x 480으로 고정된 캔버스를 제공하며, 세번째는 텍스트 스트링을 위한 리소스 번들이다.

그리기 프로그램의 툴바 동작은 상호배타적이기 때문에, 그림판은 각각의 동작에 대한 모드를 갖고 모드를 통해 수행되는 동작을 결정한다. 따라서, 사용자의 솔루션은 한 세트의 모드를 정의해야 한다. 나열형(enumerated type)을 선호한다면 나열타입의 모드를 생성할 수도 있다. 간단하게 다음과 같이 정수(integers)로 이루어진 세트를 이용할 수 있다.

   public static final int MODE_NORMAL = 0;
   public static final int MODE_LINE = 1;
   public static final int MODE_DRAWRECT = 2;
   public static final int MODE_FILLRECT = 3;
   public static final int MODE_DRAWOVAL = 4;
   public static final int MODE_FILLOVAL = 5;
   public static final int MODE_SELECT = 6;

enumeration으로 작업하는 방법에 관한 정보는 2001/8/7 자바 프로그래밍에서 enumeration사용하기를 참고하고, J2SE 1.5에서 키워드 enum 이 새롭게 추가되었으니 이를 살펴보기 바란다.

선과 도형을 그리는 등의 동작을 할 때에 이러한 그리기 동작은 마우스가 릴리즈될 때까지는 임시 버퍼에서 이루어져야 한다. (임시 영역에서는 다른 색으로 그림이 그려진다) 마우스가 릴리즈된 후에는 그 동작이 최종 결과물이 된다. 이것이 제대로 작동되기 위해서는, 모든 그리기 연산을 더블 버퍼링으로 할 필요가 있다. 사용자가 메뉴에서 특정 동작을 선택하면, 프로그램은 단지 그림판(drawing canvas)을 재설정하기 위해 버퍼를 클리어하면 된다.

Normal 메뉴 동작에서 프로그램은 마우스의 움직임을 추적해서 그림을 그린다. 마우스를 다운하면 프로그램은 마지막 점에서부터 드래그된 다음 점으로 라인을 그린다.

Normal 이외의 메뉴에서는 프로그램은 마우스가 다운되기 시작한 지점을 저장하고, 선택된 영역에 동적으로 그림을 그린다. 각각의 메뉴를 선택해서 선으로 이루어진 직사각형과 임의대로 칠해진 직사각형 혹은 타원을 간단히 그릴 수 있다.

색이나 선의 두께(stroke size)는 메뉴에서 설정한다. 배경색과 전경색을 설정하기 위해서는 JColorChooser를 사용하는데, 이에 관한 내용은 1999/11/24 Color Choosers를 참고하기 바란다. 선의 두께를 설정하는 작업은 2003/5/20 Drawing Dashed Lines with Stroke을 참고하는데 이 테크팁의 후반부에서 제공하는 솔루션은 두꺼운 선만을 사용하고 있다. dynamic dash phases의 지원을 추가해서 스킬을 한단계 업그레이드시켜보자.

Stroke SizeRotate 메뉴 아이템을 만들기 위해서는, 숫자 값을 받을 수 있도록 JOptionPane 을 사용해야 한다. 프로그램은 입력 값을 받는 입력 필드를 갖거나 아니면 가능한 값들을 몇 개 보여주고 사용자가 이 가운데 하나를 고를 수 있도록 하는 방법을 사용한다. 대개 후자의 방법이 에러를 발생할 확률이 낮다. 후자의 방법을 선택했을 때 선택 가능한 선 두께를 보여주는 예를 보자.

    Object[] possibleValues = 
      { "1", "1.5", "2", "2.5", 
        "3", "3.5", "4", "4.5", "5" };
    Object selectedValue = JOptionPane.showInputDialog(
        canvas, res.getString("Choose_stroke_size"), 
        res.getString("Stroke_Size"),
        JOptionPane.INFORMATION_MESSAGE, null,
        possibleValues, possibleValues[0]);
    if (selectedValue != null) {
      float size = 
        Float.parseFloat((String)selectedValue);
      canvas.setStrokeSize(size);
    }
rotangl

기본적으로, 위의 코드는 선택 가능한 값들로 이루어진 하나의 배열을 만들고 초기 디폴트를 선택하고 있다. 변수 res 는 보여주고자 하는 스트링을 가져오는 리소스 번들을 나타낸다.

사용자가 하나의 영역을 선택하기 전까지는, Edit 하위 메뉴에서 선택하는 동작은 작동하지 않는다는 것을 기억하자.

Rotate 액션은 AffineTransform를 사용하고 관련 내용은 2003/9/9 AffineTransform 이해하기에서 볼 수 있다. 이미지를 회전시킬 때에는, 이미지의 원점(origin)이 아닌 영역의 중심으로부터 이미지가 회전 된다는 것을 기억하자. 또한 회전각을 라디안으로 바꿔줘야하는 것도 잊지 말자.

뒤집기(flipping) 동작은 변환(transform)이나 Graphics의 많은 drawImage 메소드 중에 하나를 사용하여 작성할 수 있다. 수평으로 뒤집는 동작을 하는 코드가 있다.

   g.drawImage(buffer,
      selectedArea.x + selectedArea.width, 
        selectedArea.y, 
      selectedArea.x, selectedArea.y + 
        selectedArea.height,
      selectedArea.x, selectedArea.y, 
      selectedArea.x + selectedArea.width, 
      selectedArea.y + selectedArea.height, this);

위의 코드에서 위치 인수(location arguments)는 4개의 세트 내에 존재한다. 자세히 살펴보면 2개의 세트에서 x좌표들이 바뀌어있는 것을 발견할 수 있는데 이것이 대상을 수평으로 뒤집는 결과를 낳는다. 수직으로 뒤집기를 원하면 y좌표를 바꾸면 된다.

마지막으로 언급할 동작은 이미지의 저장에 관한 것이다. 저장될 장소를 선택하기 위해서는 JFileChooser를 사용한다. (1999/6/15 file choosers참조) 1999/10/21 "Creating Image Thumbnails"는 이미지를 저장하는 방법을 설명한다. 하지만 이미지를 저장하는 좀 더 효과적이고 새로운 방법은 ImageIO 클래스를 사용하는 것이다. ImageIO 클래스의 사용은 formal documentation과 이를 다루게 될 이후의 테크팁을 참고하기 바란다.

http://java.sun.com/developer/jdctechti ··· 1223.txt에서 이번 과제의 솔루션을 찾을 수 있다. 앞서 설명했듯이 이 솔루션은 3개의 클래스로 이루어져 있다. 하나는 GUI를 나타내고, 두번째 클래스는 캔버스를 제공하며 세번째는 텍스트 스트링을 위한 리소스 번들이다.

그리기 프로그램에 좀 더 많은 기능을 넣고자 한다면 다음을 참고할 수가 있다.

  • 사용자가 텍스트를 추가할 수 있도록 한다. 사용자가 사용하고 싶은 폰트나 스타일, 사이즈 등을 선택할 수 있도록 한다.
  • 다른 애플리케이션으로부터 혹은 다른 애플리케이션으로 이미지를 자르고 붙이는 것을 지원하도록 한다.
  • dashed lines과 테두리가 있는 도형을 지원한다.
  • 도형의 패턴을 채우는 기능을 추가한다.
  • undo /redo 기능을 추가한다.
  • JPG의 압축레벨을 지정하는 것을 포함하여 이미지를 여러 가지 포맷으로 저장하는 옵션을 준다.
  • PNG로 저장했을 때, 사용자가 투명도를 마음대로 조정할 수 있게 한다.

즐겨 사용하는 그리기 프로그램에서 찾을 수 있는 옵션을 예제에 추가해 보자. 이렇게 추가되는 옵션에 대한 솔루션은 독자에게 주어진 과제이다. 프로그램에 추가할 수 있는 기능을 찾으려면 Core Java Technologies Tech Tips의 리스트를 검색해보자.

"Java SE" 카테고리의 다른 글

2004/01/06 14:21 2004/01/06 14:21

TRACKBACK :: http://blog.sdnkorea.com/blog/trackback/245

댓글을 달아 주세요

  1. 이우철  수정/삭제  댓글쓰기

    늘 좋은 정보 감사합니다
    개발자뿐만 아니라 사용자들에게도 유익한 정보 감사

    2007/09/07 20:30
  2. 박정숙  수정/삭제  댓글쓰기

    좋은 정보 감사해요~

    2007/09/19 05:51
  3. 김형국  수정/삭제  댓글쓰기

    자바게임프로그래머에게 유용한 정보일 것같네요~
    감사합니다.

    2007/09/19 15:34
[로그인][오픈아이디란?]

◀ Prev 1  ... 598 599 600 601 602 603 604 605 606  ... 626  Next ▶