. 차일드 만들기

Dangeun7까지 당근의 모습은 조금 단순하다. 일반적인 MDI 프레임에 문서창만 있으며 기껏해야 검색결과창이 밑에 열리는 정도여서 썰렁하기까지 하다. 다른 편집기들을 보면 갖가지 명령 버튼으로 장식된 화려한 툴바, 상세한 정보를 보여주는 상태란은 기본적으로 구비되어 있고 미니 탐색기를 내장하고 있는가 하면 상용구나 함수목록 윈도우가 따로 열리기도 한다. 이외에도 문자코드표, 템플릿, 파일탭, HTML 태그창, 작업 기록 등의 각종 윈도우들이 아무 곳에나 배치될 수 있는 도킹 기능을 제공하는 것들도 있다.

이러한 화면 구성 요소들은 단순한 장식이 아니라 훌륭한 편집 보조 도구이다. 사용자에게 편집과 관련된 상세한 정보를 보여주고 사용자의 명령을 적극적으로 받아들이려면 많은 차일드 윈도우들이 필요하다. 이 장에서는 당근의 내부적인 기능 강화보다는 외부적인 모양 꾸미기를 할 것이다. Dangeun8 프로젝트를 만들고 환골탈태를 시작해보도록 하자. 이 장의 실습이 끝나면 당근도 그럭저럭 봐 줄만한 모양으로 바뀌어 있을 것이다.

당근의 차일드 윈도우는 앞장에서 만들었던 검색결과창까지 포함해서 총 5개이다. 상용 편집기에 비하면 많은 숫자는 아니지만 편집에 꼭 필요한 차일드는 모두 포함시켰다. 차일드 윈도우는 프로그램이 시작되면서 생성되어 종료될 때까지 생명을 유지하므로 그 핸들과 관련 변수들은 모두 전역으로 선언해야 한다. 다음 변수들을 Dangeun.cpp에 추가하도록 하자.

 

HWND hToolBar;

HWND hStatus;

HWND hFileWnd;

HWND hTabFrame;

HWND hFileTab;

HCURSOR hCurHorz, hCurVert;

int iDrag;

int DragOriginal;

HWND hFileTree, hFilter;

HIMAGELIST hFileImg;

HIMAGELIST hTabImg;

HFONT hGul9;

차일드는 물론이고 그 차일드의 차일드들에 대한 핸들, 차일드 윈도우 운용에 필요한 리소스와 전역 플래그들을 한꺼번에 선언하였다. 위쪽부터 차례대로 툴바, 상태란, 파일창, 파일탭의 핸들이다. 툴바와 상태란은 컨트롤이므로 CreateWindow 함수로 바로 생성할 수 있지만 파일창과 파일탭은 일반 윈도우이므로 윈도우 클래스를 먼저 선언해야 한다. WinMain에 이 두 차일드를 위한 윈도우 클래스를 선언하도록 하자.

 

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

            ,LPSTR lpszCmdParam,int nCmdShow)

{

     ....

     WndClassEx.lpszClassName="DGFile";

     WndClassEx.lpfnWndProc=(WNDPROC)DGFileProc;

     RegisterClassEx(&WndClassEx);

 

     WndClassEx.lpszClassName="DGTabFrame";

     WndClassEx.lpfnWndProc=(WNDPROC)DGTabProc;

     RegisterClassEx(&WndClassEx);

 

검색 결과창과 마찬가지로 아이콘이나 메뉴는 가지지 않으며 여분 메모리도 필요없다. 윈도우 클래스의 이름과 윈도우 프로시저의 주소로만 윈도우 클래스를 등록하였다. 윈도우 프로시저는 일단 다음처럼 껍데기만 만들어 두도록 하자.

 

LRESULT CALLBACK DGFileProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

     HDC hdc;

     PAINTSTRUCT ps;

 

     switch(iMessage) {

     case WM_PAINT:

          hdc=BeginPaint(hWnd, &ps);

          TextOut(hdc, 10, 10, "나 파일창", 9);

          EndPaint(hWnd, &ps);

          return 0;

     }

     return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

 

LRESULT CALLBACK DGTabProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

     HDC hdc;

     PAINTSTRUCT ps;

 

     switch(iMessage) {

     case WM_PAINT:

          hdc=BeginPaint(hWnd, &ps);

          TextOut(hdc, 2, 2, "나 파일탭", 9);

          EndPaint(hWnd, &ps);

          return 0;

     }

     return(DefWindowProc(hWnd,iMessage,wParam,lParam));

}

 

기능을 구현하는 코드는 아직 작성하지 않았으며 작업영역에 자기 이름만 출력하도록 해놓았다. 차일드를 생성 및 배치, 관리하는 실습부터 먼저 해야 하기 때문에 일단은 껍데기에 불과하지만 이 함수들이 필요하다. 다음 함수는 툴바를 생성한다. 툴바 컨트롤은 툴 버튼에 대한 정보와 각종 옵션들을 필요로 하기 때문에 따로 생성 함수를 만들어 두었다. 이 함수도 나중에 따로 분석해 볼 것이다.

 

void CreateToolBar(BOOL bText, BOOL bBig)

{

     TBBUTTON ToolBtn[13]={

          {0,IDM_FILE_NEW,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,0},

          {1,IDM_FILE_OPEN,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,1},

          {2,IDM_FILE_SAVE,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,2},

          {4,0,0,TBSTYLE_SEP,0,0},

          {3,IDM_EDIT_CUT,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,3},

          {4,IDM_EDIT_COPY,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,4},

          {5,IDM_EDIT_PASTE,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,5},

          {4,0,0,TBSTYLE_SEP,0,0},

          {6,IDM_EDIT_UNDO,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,6},

          {7,IDM_EDIT_REDO,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,7},

          {4,0,0,TBSTYLE_SEP,0,0},

          {8,IDM_VIEW_WORDWRAP,TBSTATE_ENABLED,TBSTYLE_CHECK,0,0,0,8},

          {9,IDM_SEARCH_FIND,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,9},

     };

     TCHAR *szToolText="새파일\0열기\0저장\0자르기\0복사\0붙이기\0취소\0재실행\0개행\0찾기\0";

     int bx,by;

     UINT_PTR wID;

    

     if (hToolBar) {

          DestroyWindow(hToolBar);

     }

 

     if (bBig) {

          wID=IDB_TOOLBARBIG;

          bx=24;

          by=22;

     } else {

          wID=IDB_TOOLBAR;

          bx=16;

          by=15;

     }

 

     hToolBar=CreateToolbarEx(g_hFrameWnd, WS_CHILD | WS_VISIBLE

          | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT ,

          99, 10, g_hInst, wID, ToolBtn, 13,

          bx,by,bx,by,sizeof(TBBUTTON));

 

     if (bText) {

          SendMessage(hToolBar,TB_ADDSTRING,NULL,(LPARAM)szToolText);

     }

     SendMessage(hToolBar,TB_AUTOSIZE,0,0);

}

 

전역 변수와 윈도우 클래스, 윈도우 프로시저 등을 모두 작성했으므로 이제 OnCreate에서 차일드를  생성하도록 하자. 검색결과창 생성문 뒤에 나머지 차일드를 생성하는 코드를 다음과 같이 작성한다. 툴바, 상태란 등은 설정상태에 따라 생성 방법이 달라지기 때문에 설정상태를 먼저 읽은 후에 차일드를 생성해야 한다. 차일드 생성에 필요한 리소스들은 이미 만들어져 있다.

 

int OnCreate(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

     ....

 

     hdc=GetDC(NULL);

     for (i=1;i<10;i++) {

          arCustomFont[i].lfHeight=arCustomFont[i].lfHeight*GetDeviceCaps(hdc,LOGPIXELSY)/72;

     }

    hGul9=CreateFont(9*GetDeviceCaps(hdc,LOGPIXELSY)/72,0,0,0,0,0,0,0,HANGEUL_CHARSET,3,2,1,

        VARIABLE_PITCH | FF_ROMAN,"굴림");

     ReleaseDC(NULL,hdc);

 

     ....

 

     hOutput=CreateWindowEx(WS_EX_CLIENTEDGE,"DGOutput",NULL,WS_CHILD | WS_VISIBLE,

          0,0,0,0,hWnd,NULL,g_hInst,NULL);

    CreateToolBar(Option.bToolBarText, Option.bToolBarBig);

    hStatus=CreateStatusWindow(WS_CHILD | WS_VISIBLE, "", hWnd,0);

    hFileWnd=CreateWindowEx(WS_EX_CLIENTEDGE,"DGFile",NULL,WS_CHILD | WS_VISIBLE,

        0,0,0,0,hWnd,NULL,g_hInst,NULL);

    hTabFrame=CreateWindowEx(0,"DGTabFrame",NULL,WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,

        0,0,0,25,hWnd,NULL,g_hInst,NULL);

     ....

 

검색 결과창 다음에 툴바, 상태란, 파일창, 파일탭 순으로 차일드들이 순서대로 생성된다. 모든 차일드는 한글 윈도우즈에서 가장 보기 좋은 글꼴인 굴림 9포인트의 글꼴을 사용할 것이다. 그래서 이 컨트롤들이 사용할 hGul9 폰트를 미리 생성해두었다. 이 폰트는 실행중에 계속 유지되며 OnDestroy에서 파괴된다.

 

void OnDestroy(HWND hWnd,WPARAM wParam,LPARAM lParam)

{

....

     DeleteObject(hGul9);

}

 

여기까지 코드를 작성한 후 실행해도 아직 차일드는 보이지 않을 것이다. 왜냐하면 차일드의 폭과 높이가 아직 제대로 설정되지 않았기 때문이다. 차일드는 작업영역의 정해진 부분에 배치되기 때문에 생성할 때 위치와 크기를 결정할 수 없으며 부모 윈도우의 크기가 변경되는 OnSize에서 매번 재배치해야 한다.