. 툴 버튼의 스타일

툴바의 스타일과는 별도로 툴 버튼도 개별적으로 스타일을 가지며 버튼을 등록할 때 TBBUTTON 구조체의 fsStyle 멤버로 버튼의 스타일을 지정한다. 물론 TB_SETBUTTONINFO 메시지나 TB_SETSTYLE 등의 메시지를 사용하면 언제든지 버튼의 스타일을 변경할 수 있다. 다음 예제는 툴 버튼의 모든 스타일을 테스트하기 위해 만든 것이다. 각각의 스타일을 가지는 버튼을 만들고 테스트해 보도록 하자.

 

#include <commctrl.h>

#include "resource.h"

#define ID_TOOLBAR 100

HWND hToolBar;

COLORREF Back;

DWORD iMode;

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

{

   HDC hdc;

   PAINTSTRUCT ps;

   RECT crt;

   HBRUSH hBrush;

   TBBUTTON ToolBtn[]={

      {0,10,TBSTATE_ENABLED,TBSTYLE_BUTTON,0,0,0,0},

      {5,0,0,TBSTYLE_SEP,0,0,0,0},

      {1,11,TBSTATE_ENABLED | TBSTATE_CHECKED,TBSTYLE_CHECKGROUP,0,0,0,1},

      {2,12,TBSTATE_ENABLED,TBSTYLE_CHECKGROUP,0,0,0,2},

      {3,13,TBSTATE_ENABLED,TBSTYLE_CHECKGROUP,0,0,0,3},

      {5,0,0,TBSTYLE_SEP,0,0,0,0},

      {4,14,TBSTATE_ENABLED,TBSTYLE_CHECK | TBSTYLE_AUTOSIZE,0,0,0,4},

      {5,15,TBSTATE_ENABLED,TBSTYLE_DROPDOWN | TBSTYLE_NOPREFIX,0,0,0,5},

      {6,16,TBSTATE_ENABLED,TBSTYLE_DROPDOWN | 0x80/*BTNS_WHOLEDROPDOWN*/,0,0,0,6}

   };

   TCHAR Mes[]=" 버튼의 여러 속성들을 테스트합니다.";

   TCHAR *szString="명령버튼\0빨간색\0초록색\0파란색\0투명\0&Drop\0&Drop2\0";

 

   switch(iMessage) {

   case WM_CREATE:

      InitCommonControls();

      hToolBar=CreateToolbarEx(hWnd, WS_CHILD | WS_VISIBLE | WS_BORDER

          | TBSTYLE_FLAT,

          ID_TOOLBAR, 10, g_hInst, IDB_BITMAP1, ToolBtn, 9,

          16,16,16,16,sizeof(TBBUTTON));

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

      // SendMessage(hToolBar,TB_SETEXTENDEDSTYLE,0,(LPARAM)TBSTYLE_EX_DRAWDDARROWS);

      Back=RGB(255,0,0);

      iMode=OPAQUE;

      return 0;

   case WM_COMMAND:

      switch (LOWORD(wParam)) {

      case 10:

          MessageBox(hWnd,"푸쉬 버튼입니다","알림",MB_OK);

          break;

      case 11:

          Back=RGB(255,0,0);

          InvalidateRect(hWnd,NULL,TRUE);

          break;

      case 12:

          Back=RGB(0,255,0);

          InvalidateRect(hWnd,NULL,TRUE);

          break;

      case 13:

          Back=RGB(0,0,255);

          InvalidateRect(hWnd,NULL,TRUE);

          break;

      case 14:

          if (SendMessage(hToolBar,TB_ISBUTTONCHECKED,14,0)) {

             iMode=TRANSPARENT;

          } else {

             iMode=OPAQUE;

          }

          InvalidateRect(hWnd,NULL,TRUE);

      }

      return 0;

   case WM_NOTIFY:

      switch (((LPNMHDR)lParam)->code) {

      case TBN_DROPDOWN:

          HMENU hPopup;

          POINT pt;

          hPopup=CreatePopupMenu();

          AppendMenu(hPopup,MF_STRING,0,"팝업 하나");

          AppendMenu(hPopup,MF_STRING,1,"팝업 ");

          AppendMenu(hPopup,MF_STRING,2,"팝업 ");

 

          GetCursorPos(&pt);

          TrackPopupMenu(hPopup,TPM_LEFTALIGN,pt.x,pt.y,0,hWnd,NULL);

          DestroyMenu(hPopup);

 

          return TBDDRET_DEFAULT;

      }

      return 0;

   case WM_PAINT:

      hdc=BeginPaint(hWnd, &ps);

      GetClientRect(hWnd,&crt);

      hBrush=CreateSolidBrush(Back);

      FillRect(hdc,&crt,hBrush);

      DeleteObject(hBrush);

      SetBkMode(hdc,iMode);

      TextOut(hdc,10,50,Mes,lstrlen(Mes));

      EndPaint(hWnd, &ps);

      return 0;

   case WM_SIZE:

      SendMessage(hToolBar,TB_AUTOSIZE,0,0);

      return 0;

   case WM_DESTROY:

      PostQuitMessage(0);

      return 0;

   }

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

}

 

실행해 보면 빨간색 화면에 텍스트가 출력되어 있다. 화면의 색상은 세 개의 체크 그룹 버튼으로 변경할 수 있으며 텍스트의 투명 여부는 투명 체크 버튼으로 선택한다. 실행중의 모습은 다음과 같다.

첫번째 버튼이 명령 버튼인데 가장 흔하고 가장 쉬운 스타일이다. 이 버튼을 누르면 쑥 들어간 모양이 되며 다시 버튼을 놓으면 부모 윈도우로 WM_COMMAND 메시지가 전달된다. 이때 LOWORD(wParam)으로는 버튼의 명령 ID가 전달된다. 툴바에 포함되어 있다는 차이점이 있을 뿐 표준 버튼 컨트롤의 동작과 완전히 동일하다. 단순히 명령을 내리고자 할 때 이 스타일의 버튼이 사용된다.

두번째 버튼은 구분 여백이다. TBSTYLE_SEP 스타일을 가지는 버튼은 실제로 버튼이 아니라 버튼간의 간격을 띄우기 위한 빈 공간으로 사용되며 FLAT 툴바에서는 수직선으로 나타난다. 이때 TBBUTTON 구조체의 iBitmap 멤버로 구분 여백의 폭을 지정할 수 있다. 예제에서는 구분 여백의 폭을 5픽셀로 지정하였다. 많은 버튼들이 일렬로 밀착되어 있으면 보기에도 갑갑하고 버튼을 선택하기도 어려워지므로 버튼을 기능별로 그룹짓고 중간 중간에 구분 여백을 넣어 주는 것이 보기 좋다.

세번째~다섯번째 버튼은 체크 그룹을 구성한다. 체크 그룹은 인접한 세 버튼이 하나의 그룹이 되며 셋 중 하나만 선택될 수 있다. 그룹 중 한 버튼이 눌러지면 그룹에 속한 나머지 버튼은 선택이 해제된다. 예제에서 이 체크 그룹은 세 가지 색상중 하나를 선택하도록 하는데 두 가지 이상의 색상이 동시에 선택될 수는 없으므로 체크 그룹을 이루어야 한다. 표준 컨트롤의 라디오 버튼과 개념상 동일하다.

체크 버튼은 두가지 상태 중 하나를 선택할 때 사용하며 누를 때마다 선택 상태가 토글된다. 보이기/숨기기, 선택/비선택, 읽기전용/쓰기가능 등과 같이 두가지 상태를 조정하기 위한 용도로 적합하다. 예제의 투명 버튼은 투명/불투명 둘 중 하나를 선택하며 이 버튼이 선택되어 있으면 텍스트가 투명하게 출력되고 그렇지 않으면 불투명하게 출력된다. 표준 컨트롤의 체크 버튼과 개념상 동일하다.

이 버튼도 다른 버튼과 마찬가지로 눌러지면 WM_COMMAND 메시지를 보내는데 이때 단순히 버튼이 눌러졌다는 정보만 전달될 뿐 현재 버튼의 상태는 전달되지 않으므로 TB_ISBUTTONCHECKED 메시지를 보내 버튼의 현재 상태를 조사해야 한다. 이 메시지를 보낸 결과 선택되어 있으면 투명 모드로 바꾸고 그렇지 않으면 불투명 모드로 바꾼다. 버튼의 상태는 이 메시지외에 TB_GETSTATE나 다음과 같이 TB_GETBUTTONINFO 메시지로도 조사할 수 있다.

 

TBBUTTONINFO bi;

bi.cbSize=sizeof(TBBUTTONINFO);

bi.dwMask=TBIF_STATE;

bi.idCommand=14;

SendMessage(hToolBar,TB_GETBUTTONINFO,14,(LPARAM)&bi);

if (bi.fsState & TBSTATE_CHECKED) {

   ....

 

dwMask에 알고 싶은 값을 넣고 idCommand에 대상 버튼의 명령 ID를 대입한 후 이 메시지를 보내면 그 결과가 fsState 멤버로 리턴된다. fsState에 TBSTATE_CHECKED 플래그가 설정되어 있으면 버튼이 체크되어 있는 것이다.

TBSTYLE_NOPREFIX 스타일은 버튼의 캡션중 & 문자가 있으면 이 문자를 어떻게 처리할 것인가를 지정한다. Drop, Drop2버튼이 모두 & 문자를 가지고 있는데 TBSTYLE_NOPROFIX 스타일을 가지는 Drop 버튼은 &문자를 그대로 보여주는 반면 Drop2 버튼은 &문자 다음에 있는 D문자에 밑줄을 그어 보여준다. 메뉴의 캡션을 툴바의 텍스트로 재사용할 경우에 이 스타일로 &문자의 처리를 적절히 지정해야 한다.

툴 바의 버튼들은 통상 동일한 크기를 가진다. 버튼의 폭은 가장 긴 텍스트의 폭에 맞추어지는데 TBSTYLE_AUTOSIZE 스타일을 가지는 버튼은 이 폭을 사용하지 않으며 자기 자신의 텍스트 폭에 맞추어진다. 예제에서 첫번째 명령버튼의 텍스트가 제일 길기 때문에 이 텍스트의 폭에 맞게 버튼의 폭이 결정되는데 투명 버튼은 TBSTYLE_AUTOSIZE 스타일을 가지고 있기 때문에 다른 버튼보다는 폭이 좁게 나타난다. 툴 바의 버튼들은 가급적이면 동일한 폭을 가지는 것이 보기에 좋으므로 일관성을 위해 이 스타일은 사용하지 않는 것이 좋다.

TBSTYLE_DROPDOWN 스타일을 가지는 버튼은 드롭 다운 메뉴를 여는 용도로 많이 사용된다. 이 스타일을 가지는 버튼을 선택하면 WM_COMMAND 메시지 대신 TBN_DROPDOWN 통지 메시지를 보내 주는데 이 때 팝업 메뉴를 열어 보여 주면 된다. 물론 더 복잡한 정보를 전달하기 위해서는 팝업 대화상자를 열 수도 있다. 예제에서는 단순히 팝업 메뉴를 만들어 열기만 했으며 메뉴가 선택되었을 때는 처리하지 않았다.

BTNS_WHOLEDROPDOWN 스타일은 버튼 이미지 옆에 아래쪽 화살표를 보여 주어 이 버튼을 누르면 팝업 메뉴가 열린다는 것을 명확하게 표현한다는 차이점이 있다. 이 스타일값은 commctrl.h 헤더 파일에 0x80으로 정의되어 있으며 _WIN32_IE가 0x500이상일 때만 사용할 수 있다. 비주얼 C++ 7.0과 함께 배포되는 commctrl.h에는 이 스타일값이 정의되어 있으나 6.0의 commctrl.h에는 값이 정의되어 있지 않으므로 예제에서는 0x80을 직접 사용하였다.

드롭 다운 버튼의 동작 방식은 툴 바가 TBSTYLE_EX_DRAWDDARROWS 확장 스타일을 가질 때 달라진다. 이 확장 스타일이 적용되면 드롭 다운 버튼의 오른쪽에는 별도의 분리된 화살표 버튼이 나타난다. 다음은 이 확장 스타일을 주었을 때와 그렇지 않을 때를 비교한 것이다. 예제에는 이 확장 스타일 지정문이 주석으로 처리되어 있는데 주석을 풀어가며 비교해 보기 바란다.

  

분리된 화살표 버튼이 있을 때 드롭 다운 버튼 자체는 WM_COMMAND 메시지를 보내고 화살표 버튼이 TBN_DROPDOWN 통지 메시지를 대신 보낸다. 명령 자체에 여러 가지 옵션이 있고 그 중 디폴트가 있을 때 이런 스타일의 드롭 다운 버튼이 적절하다. 가장 대표적인 예는 실행 취소 툴바이다.

드롭 다운 버튼을 누르면 취소 가능한 명령들의 목록을 보여 주며 취소 버튼 자체는 가장 최근에 편집한 내용을 취소한다. 바로 직전의 명령을 취소할 때는 취소 버튼을 사용하고 편집 기록을 보고 취소할 범위를 선택하고 싶을 때는 드롭 다운을 열면 된다. 보기에도 직관적이고 툴바의 면적도 많이 차지하지 않으므로 실전에서 활용할만하다.