.텍스트 옵션 설정

텍스트는 다른 객체에 비해 글꼴이 적용되기 때문에 설정할 있는 옵션의 수도 많다. 글자의 크기나 색상은 사용자가 입력하거나 선택하도록 있지만 글꼴은 시스템마다 설치된 목록이 달라지므로 직접 입력하는 방법은 좋지 않다. 글꼴을 선택하려면 열거를 먼저 해야 한다. 열거한 결과를 저장하기 위해 다음 변수를 추가하도록 하자.

 

LOGFONT logfont[500];

int FontNum;

 

열거된 변수들의 목록을 저장하기 위해 크기 500 LOGFONT 배열을 선언했으며 열거된 글꼴의 개수를 저장하기 위해 FontNum이라는 정수형 변수를 선언했다. 열거 함수에서는 열거된 결과를 배열에 일단 모두 저장해 둔다.

 

int CALLBACK EnumFamCallBack(ENUMLOGFONT FAR *lpelf, NEWTEXTMETRIC FAR *lpntm,

                       int FontType, LPARAM lParam)

{

   if (FontNum < 500) {

      if (lpelf->elfLogFont.lfFaceName[0] != '@') {

          logfont[FontNum] = lpelf->elfLogFont;

          FontNum++;

      }

      return TRUE;

   } else {

      return FALSE;

   }

}

 

void ReEnum()

{

   HDC hdc;

 

   FontNum=0;

   hdc=GetDC(hWndMain);

   EnumFontFamilies(hdc, NULL, (FONTENUMPROC)EnumFamCallBack, (LPARAM)NULL);

   ReleaseDC(hWndMain, hdc);

}

 

속성 대화상자에서 콤보 박스에 열거된 글꼴의 목록을 보여 주고 선택할 있도록 한다. 또한 글자 크기와 색상에 대한 처리도 해야 한다. 속성 대화상자 프로시저를 다음과 같이 수정하도록 하자.

 

BOOL CALLBACK PropertyDlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)

{

   ....

   switch(iMessage) {

   case WM_INITDIALOG:

      if (FontNum==0) {

          ReEnum();

      }

      for (i=0;i<FontNum;i++) {

         SendDlgItemMessage(hDlg,IDC_CBFONTFACE,CB_ADDSTRING,0,(LPARAM)logfont[i].lfFaceName);

      }

 

      for (i=0;i<sizeof(arColor)/sizeof(arColor[0]);i++) {

          SendDlgItemMessage(hDlg,IDC_CBLINECOLOR,CB_ADDSTRING,0,(LPARAM)arColor[i]);

          SendDlgItemMessage(hDlg,IDC_CBPLANECOLOR,CB_ADDSTRING,0,(LPARAM)arColor[i]);

          SendDlgItemMessage(hDlg,IDC_CBFONTCOLOR,CB_ADDSTRING,0,(LPARAM)arColor[i]);

      }

      SendDlgItemMessage(hDlg,IDC_SPLINEWIDTH,UDM_SETRANGE,0,MAKELONG(10,0));

 

      Obj=(DObject *)lParam;

      SetDlgItemInt(hDlg,IDC_EDLINEWIDTH,Obj->LineWidth,FALSE);

      for (i=0;i<sizeof(arColor)/sizeof(arColor[0]);i++) {

          if (arColor[i] == Obj->LineColor) {

             break;

          }

      }

      SendDlgItemMessage(hDlg,IDC_CBLINECOLOR,CB_SETCURSEL,i,0);

      for (i=0;i<sizeof(arColor)/sizeof(arColor[0]);i++) {

          if (arColor[i] == Obj->PlaneColor) {

             break;

          }

      }

      SendDlgItemMessage(hDlg,IDC_CBPLANECOLOR,CB_SETCURSEL,i,0);

      SendDlgItemMessage(hDlg,IDC_SPFONTSIZE,UDM_SETRANGE,0,MAKELONG(72,6));

      SetDlgItemInt(hDlg,IDC_EDFONTSIZE,Obj->FontSize,FALSE);

      for (i=0;i<sizeof(arColor)/sizeof(arColor[0]);i++) {

          if (arColor[i] == Obj->FontColor) {

             break;

          }

      }

      SendDlgItemMessage(hDlg,IDC_CBFONTCOLOR,CB_SETCURSEL,i,0);

      for (i=0;i<FontNum;i++) {

          if (lstrcmp(logfont[i].lfFaceName,Obj->FontFace) == 0) {

             break;

          }

      }

      SendDlgItemMessage(hDlg,IDC_CBFONTFACE,CB_SETCURSEL,i,0);

      if (Obj->Type != -1) {

          if (Obj->Type != DT_TEXT) {

             EnableWindow(GetDlgItem(hDlg,IDC_EDFONTSIZE),FALSE);

             EnableWindow(GetDlgItem(hDlg,IDC_CBFONTCOLOR),FALSE);

             EnableWindow(GetDlgItem(hDlg,IDC_CBFONTFACE),FALSE);

          } else {

             EnableWindow(GetDlgItem(hDlg,IDC_EDLINEWIDTH),FALSE);

             EnableWindow(GetDlgItem(hDlg,IDC_CBLINECOLOR),FALSE);

          }

      }

      return TRUE;

   case WM_MEASUREITEM:

      ....

   case WM_DRAWITEM:

      ....

   case WM_COMMAND:

      switch (wParam) {

      case IDOK:

          ....

          i=SendDlgItemMessage(hDlg,IDC_CBFONTCOLOR,CB_GETCURSEL,0,0);

          Obj->FontColor=arColor[i];

          Obj->FontSize=GetDlgItemInt(hDlg,IDC_EDFONTSIZE,NULL,FALSE);

          GetDlgItemText(hDlg,IDC_CBFONTFACE,Obj->FontFace,32);

          EndDialog(hDlg,IDOK);

          ....

 

대화상자를 열자 마자 열거가 되어 있는지 조사해 보고 FontNum 0이라면 이때 열거를 하도록 했다. 글꼴 열거를 프로그램 시작시인 OnCreate에서 하지 않고 최초로 대화상자가 열릴 하는 이유는 프로그램의 시작 속도를 빠르게 하기 위해서이다. 매번 프로그램을 시작할 때마다 글꼴 열거를 한다면 기동 시간이 오래 걸려 사용자들이 짜증을 내지만 대화상자가 열릴 때는 사용자들이 어느 정도의 인내심을 발휘하여 기다리므로 이때 열거를 하는 것이 좋다. 물론 일단 한번 열거가 되면 다시 열거하지는 않는다.

열거된 결과를 폰트 콤보 박스에 출력하고 색상 콤보 박스도 면이나 선의 색상과 마찬가지로 초기화한다. 글꼴 색상도 오너 드로우로 되어 있는데 오너 드로우 코드가 이미 작성되어 있으므로 이상 여분의 코드를 작성할 필요는 없다. 컨트롤 초기화 파라미터로 전달된 Obj 객체의 글꼴 설정을 컨트롤에 출력한다. 그리고 전역 옵션이 아닌 경우는 텍스트 객체인가 아닌가에 따라 컨트롤을 적당히 사용금지 시킨다. 텍스트 객체는 선굵기, 선색상 옵션을 사용하지 않으며 글꼴과 관련된 옵션은 다른 객체에는 필요치 않다.

IDOK에서는 편집된 결과를 다시 Obj 읽어 온다. 여기까지 코드를 작성한 테스트해 보면 전역 글꼴 설정과 개별 텍스트 객체의 글꼴을 모두 조정할 있을 것이다. 글꼴과 관련된 마지막 처리는 시스템의 글꼴 설정이 바뀌었을 폰트를 다시 열거하는 것이다.

 

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

{

   ....

   case WM_FONTCHANGE:

      ReEnum();

      InvalidateRect(hCanvas,NULL,FALSE);

      return 0;

   }

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

}

 

시스템에 새로운 글꼴이 추가되거나 삭제되면 WM_FONTCHANGE 메시지가 모든 레벨 윈도우로 보내지는데 메시지를 받았을 글꼴 목록을 다시 작성해야 한다. 그렇지 않으면 새로 추가되었거나 삭제된 글꼴에 대한 정보를 없게 것이다. 이미 그려진 텍스트 객체중에 글꼴을 사용하는 것이 있을 수도 있으므로 캔버스도 다시 그려야 한다.