티스토리 툴바


Computer/Java / JSP2012/01/15 14:36

[그림 1] 이전 글(SWT에서의 GC, Drawable, Canvas #1. 설명)에서 사용한 것과 동일한 그림.

Control 객체가 그 객체의 paintEvent를 통하여 그림을 그릴 수 있지만, 이보다는 Control 클래스를 상속받아 그래픽 작업을 위해 설계된 특별한 클래스인 Canvas클래스를 사용하여 그림을 그리는것이 더욱 좋습니다. Canvas 클래스를 생성한 후 addPaintListener()를 통하여 페인트 리스너를 추가하거나, 사용자가 직접 정의한 Control을 상속받음으로서 그림을 그릴 수 있습니다. Canvas클래스는 그림을 그릴때 사용할 수 있는 다양한 종류의 스타일 비트를 가지고 있습니다.

Canvas의 기본적인 동작은 다음과 같습니다. 객체의 할당영역을 그리기 앞서, 객체에 할당된 전체 영역을 현재 배경색으로 칠합니다. 이때 화면이 깜박이는 현상을 볼 수 있는데 이는 paintEvent가 배경색을 칠하고, 그 위에 Canvas의 요소들을 덧칠하는 순간을 우리가 보는 것입니다. 이 현상을 방지하기 위한 방법 중 하나는, Canvas를 생성할 때 SWT.NO_BACKGROUND 스타일 비트를 사용하여 배경이 그려지지 않게 하는것입니다. 단, 이 비트를 사용할 경우, 프로그램은 영역 전체에 대하여 모든 픽셀을 직접 그려야 합니다.

위젯의 사이즈가 변경될 때에도 paintEvent가 발생합니다. 이 역시 화면을 깜박거리게 할 수 있는데, 왜냐하면 사이즈가 변경될 때마다 해당 영역에 대해 모든 요소들을 다시 그려야 하기 때문입니다. 이는 SWT.NO_REDRAW_RESIZE 스타일 비트를 사용하여 완화시킬 수 있으며, 이는 컨트롤의 사이즈가 변경되더라도 paintEvent가 발생하지 않는다는것을 의미합니다. 이는 컨트롤이 불필요하게 다시 그려지는것을 방지한다는 의미를 갖으며, 만약 크기자 증가된다고 한다면, paintEvent의 GC는 이 영역을 제외한 부분만을 다시 그리게 됩니다. 단 사각형 모양이 캔버스가 존재할 경우 사각형의 오른쪽 하단에 L이 거꾸로 된 형태가 그려질 수 있다는것이 알려졌습니다.

NO_REDRAW_RESIZE 스타일 비트는 새로 그려지는 부분에 대해서 적절히 처리해줄 경우, 고정사이즈의 그림이 GC에 그려질 때 나타나는 깜박임을 감소시킬 수 있습니다. 하지만 잘못 쓰였을 경우, NO_REDRAW_RESIZE는 치즈(cheese)라는 효과를 불러올 수 있습니다. 치즈는 다시 그려야 할 상황에 제대로 다시 그려지지 않는 부분이 있는 경우를 지칭합니다. paintEvent가 클라이언트 전 영역을 다시 그려야 하는 아래의 예시를 확인해보세요. 화면이 작아질 때에는 paintEvent가 발생하지 않기 때문에 그림이 다시 그려지지 않습니다. SWT.NO_REDRAW_RESIZE상태에서 화면이 커질 경우, paintEvent는 새로 그려야 하는 부분에 대해서만 영역을 다시 그리기 떄문에, 그리고 기존에 그려졌던 부분이 지워지지 않았기 때문에 치즈 현상이 발생하게 됩니다. 캔버스 사이즈가 증가할 때 GC는 필요한 부분만 다시 그리기 때문에 치즈 현상이 발생하게 됩니다.

shell.setLayout(new FillLayout());
final Canvas canvas = new Canvas(shell,SWT.NO_REDRAW_RESIZE);

canvas.addPaintListener(new PaintListener() {
    public void paintControl(PaintEvent e) {
        Rectangle clientArea = canvas.getClientArea();
        e.gc.setBackground(display.getSystemColor(SWT.COLOR_CYAN));
        e.gc.fillOval(0,0,clientArea.width,clientArea.height);
    }
});

이 문제를 해결하는 방법은 SWT.NONE 스타일 비트를 사용하여 GC가 크기가 커질 때 커진 부분만 새로 그리는것이 아닌, 모든 부분을 새로 그리도록 하고, 동시에 paintEvent가 셸 사이즈가 작아졌을 때에도 발생하게 하여, canvas의 전체부분이 다시 그려지게 하는 것입니다.

final Canvas canvas = new Canvas(shell,SWT.NONE);

각각의 SWT 위젯에 대해, 만약 하나이상의 영역이 다시 그려져야 할 경우, 운영체제는 다시 그려야 할 영역을 하나의 영역으로 묶어서 paintEvent를 발생하여 효율적인 처리를 가능하게 합니다. Canvas의 NO_MERGE_PAINTS 스타일 비트는 각각의 위젯에서 다시 그릴 영역을 하나로 묶지 않고, 각각의 영역에 대해 일일히 paintEvent를 호출하는 방식으로 변경합니다.

NO_BACKGROUND, NO_REDRAW_RESIZE, NO_MERGE_PAINTS 스타일 비트는 Composite와 이 하부 클래스인 Canvas, Shell, Group등에서 사용할 수 있습니다, SWT에서 허용하긴 하지만, Composite클래스의 Javadoc에서는 스타일 비트에 대해서 다음과 같이 기술합니다. "Canvas 이외의 Composite의 하위클래스에서의 사용은 정의되지 않았다". 그러므로 Canvas 클래스가 그림 그리는데에 가장 적합한 컨트롤이라 할 수 있습니다.

깜박임을 방지하는 또다른 방법은 더블 버퍼링을 사용하여 그림그리기를 한번에 처리하는 것입니다. 더블 버퍼링은 paintEvent에서 제공하는 GC기 아닌 GC에 그림을 미리 그린 후, 이것을 제공되는 GC에 복사하는 기술입니다. 이를 위하여, Canvas의 영역과 동일한 사이즈의 Image 객체를 만들고, GC(Image)를 통하여 이 객체에 그림을 그립니다. 그려진 그림(Image)은 drawImage(Image, int, int) 메소드를 호출함으로서 paintEvent의 GC로 그려지게 됩니다. 이 기술을 사용할 때 주의할 점은 몇몇 운영체제는 이미 더블버퍼링을 자체적으로 구현하고 있으므로, 결국 트리플 버퍼링이 이루어질 수 있다는 점입니다.


================
어느정도 의역을 하였습니다. 대표적으로 lientArea는 해당 영역, flatform은 운영체제, cropping 개념은 풀어서 설명했습니다. 사실 NO_BACKGROUND, NO_REDRAW_RESIZE, NO_MERGE_PAINTS는 왠만해선 사용하지 않고 SWT.NONE을 기본으로 붙여 사용합니다. 그리고 참고로 윈도우 환경에서는 더블 버퍼링을 기본으로 지원하지 않기 때문에 더블 버퍼링을 구현해 주어야 합니다. 이에대한 예제는 java2s의 Java » SWT JFace Eclipse » Image카테고리에 위치한 Double Buffer 페이지에 잘 나와있습니다. 기존의 버퍼를 저장해서 횔용하는 방법으로 더욱 좋은 효율의 더블 버퍼링을 구현하였네요, 대신 간단한 개념을 좀 복잡하게 해놔서 입문자에게는 좀 불리합니다. 그리고 생성한 GC는 dispose()로 꼭 없애는것을 잊지마세요.


원문보기

저작자 표시 비영리 변경 금지
Posted by frontjang

TRACKBACK http://frontjang.info/trackback/261 관련글 쓰기

댓글을 달아 주세요

Computer/Software2012/01/01 23:45

[그림 1] 오른쪽 마우스 버튼을 눌렀을 때 나오는 메뉴(context menu)

윈도우에서 파일이나 폴더를 선택한 후 마우스 오른쪽 버튼을 누르게 되면 메뉴(Context Menu, 한글로 뭐라고 적어야 할지 모른다)가 뜬다. 언젠가부터 블로그에 파일을 올릴때 이미지 사이즈를 축소하고, 파일명에 suffix를 붙이고 파일 확장자를 png로 해서 올리게 되었는데, 이를 어떻게 하면 간단하게 할 수 있을까 생각하다가 이번에 이를 직접 고안하기로 하였다. 위 사진을 보면 열기, 바탕 화면 배경으로 설정, 편집, 인쇄 메뉴가 있는데, 이 메뉴는 다른 파일에서의 context menu에서는 존재하지 않는 메뉴이다.

이 각각의 항목들은 파일 타입에 따라서 레지스트리에 저장이 되는데, 이러한 항목은 nirsoft에서 제작한 ShellMenuView라는 프로그램을 통해서 확인할 수 있다. 하지만 이 프로그램의 단점이라면 프로그램명 그대로 보기만 지원한다는것. 물론 항목 비활성화를 통하여 메뉴 삭제는 가능하지만 '추가'기능은 지원하지 않는다. 직접 레지스트리를 수정해야 하나.. 하고 검색도중에 발견한 Default Programs Editor. 무료에 무설치로 사용가능하다. 아래의 설명대로 위 메뉴에서 이미지 변환 메뉴를 추가하여 이미지를 마우스 클릭만으로 간단하게 변환이 가능하다. 이 작업 뿐만 아니라 특정 확장자의 파일 아이콘 변경, 파일의 설명 변경 및 파일 정보 삭제, ~으로 열기 메뉴 편집, 미디어 삽입시 기본 행동, 프로그램과 확장자의 연결 등 다양한 활동을 쉽게 변경할 수 있다. 



[그림 2, 3, 4] 프로그램 실행 후 순서대로 진행한다. 텍스트 파일에 대해 편집하고자 한다면 [그림 4]에서 txt를 입력한다.



[그림 5, 6, 7] 프로그램 명령 목록을 확인, 입력, 추가를 진행한다.

[그림 5]에서 현재 확장자와 연결된 명령들을 볼 수 있다. 항목을 추가하고자 하므로 Add... 버튼을 누르고 나오는 [그림 6]에서 항목을 알맞게 입력한다. convert.exe는 ImageMagick 패키지의 일부로서 Windows Binary 페이지에서 Portable Win32 static 버전(ImageMagick-6.7.4-Q16-windows.zip)을 다운받으면 압축파일 내에 존재한다 이를 적당한 위치에 위치시킨 후 아래의 명령을 입력한다. 

"C:\Program Files\convert.exe" "%1" -set filename:f "%%t_frontjang" -scale 800x600^> -auto-level "%%[filename:f].png" 

윈도우 환경에서는 %나 >와 같은 글자가 특수한 동작을 하므로 위와같이 두번쓰거나 ^로 escape 시켜줌으로서 사용이 가능하다. (Escape(^) 사용관련, 스위치(%) 사용관련, resize(scale) 옵션 사용관련Convert.exe 사용관련, 윈도우 환경 사용관련) ImageMagick에 대해서는 다음 포스팅에서 정리해서 다룰 예정이다.

아무튼 입력 작업을 마치면 [그림 7]과 같은 화면이 뜨게 되고, 하단의 왼쪽 버튼(Save Context Menu) 를 그냥 누르면 입력 확인 메시지가 뜨고 다른 옵션을 보고자 한다면 [그림 7]처럼 오른쪽의 ▼ 버튼을 눌러서 reg 파일로 저장할 수 있다. reg 파일로 저장한다면 다른사람들도 reg 파일만을 통하여 손쉽게 Context Menu를 변경할 수 있다.

혹시 명령줄에 입력한 명령이 올바른지 아닌지 확인하고 싶을 경우를 위하여 아래에 명령줄 체크 프로그램을 올려놓는다. 화면에 어떤 값이 입력되었는지 쉽게 알 수 있는 매우 간단한 프로그램이다. 사용 팁이라면 사용하고자 하는 프로그램과 이 프로그램을 바꿔치기해서 명령인자를 확인해 보고 그다음 다시 원상 복귀하여 안전하게 사용할 수있다. 아래에 프로그램 소스도 올려놓는다(컴파일러 옵션을 지정하지 않아 상대적으로 실행 프로그램 사이즈가 크다)



[그림 8] 프로그램 인자를 확인하는 프로그램.

#include <iostream>

main(int argc, char* argv[]){
    for(int i=0; i<argc; ++i){
            std::cout << argv[i] << " ";
    }
    getchar();
}
저작자 표시 비영리 변경 금지
Posted by frontjang

TRACKBACK http://frontjang.info/trackback/260 관련글 쓰기

댓글을 달아 주세요