. 상태란

툴바는 윈도우의 상단에 밀착되는데 비해 상태란은 보통 윈도우의 하단에 밀착되어 나타난다. 프로그램의 현재 상태나 키보드 상태 등 사용자가 프로그램 사용중에 참고할 만한 정보를 보여주며 또한 간단한 도움말을 출력하는 용도로도 사용된다. 상태란도 대부분의 프로그램에서 채용하는 추세이다. 복잡해 보이지만 알고보면 보기보다는 훨씬 더 간단하다. 메인 윈도우에서 상태란을 조작하기만 할 뿐 상태란에서 메인 윈도우로 보내지는 통지 메시지가 없는 일방향의 통신을 하기 때문이다. 물론 클릭이나 더블 클릭 등의 메시지를 보내기는 하지만 다른 컨트롤에 비해 꼭 처리해야 할 통지 메시지는 없는 셈이다.

상태란도 윈도우이므로 CreateWindow(Ex) 함수로 만들 수 있다. 윈도우 클래스로 STATUSCLASSNAME을 주면 상태란 컨트롤이 만들어지며 이때 위치나 크기를 지정하는 것은 의미가 없다. 간단한 컨트롤이므로 CreateWindow 함수보다는 다음 함수로 만드는 것이 보통이다.

 

HWND CreateStatusWindow( LONG style, LPCTSTR lpszText, HWND hwndParent, UINT wID );

 

보다시피 인수가 고작 4개뿐이다. style은 상태란의 스타일을 지정하는데 이 값은 주로 WS_CHILD | WS_VISIBLE로 주게 된다. 이외 더 지정할 수 있는 스타일은 SBT_TOOLTIPS라는 스타일이 있는데 상태란에 툴팁을 사용할 때 지정한다. lpszText는 상태란에 나타낼 초기 문자열이다. hwndParent는 부모 윈도우의 핸들이며 wID는 상태란의 ID이다. 이 함수만 호출해 주면 파트 하나만 가지는 밋밋한 상태란이 만들어진다.

 

hState=CreateStatusWindow(WS_CHILD | WS_VISIBLE, "Status Line", hWnd,0);

 

리턴되는 값은 물론 상태란의 윈도우 핸들이다. WM_CREATE에서 위와 같이 상태란을 만들면 결과는 다음과 같다.

아래쪽에 Status Line이라는 문자열을 가지는 상태란이 만들어진다. 그런데 상태란은 보통 이렇게 통째로 사용하는 경우보다 칸을 나누어 여러 가지 정보를 보여주는 것이 일반적이다. 다음은 워드와 비주얼 스튜디오의 상태란이다.

상태란을 토막 토막 잘라서 알뜰하게 사용하고 있다. 이때 상태란의 각 조각을 파트(Part)라고 하며 최대 256개까지 원하는 개수만큼 원하는 폭대로 만들 수 있다. 상태란의 메시지는 다음과 같다. SB_SETPARTS, SB_SETTEXT 정도가 알아둘 만한 메시지이다.

 

메시지

설명

SB_GETTEXT

wParam으로 지정한 파트의 텍스트를 구한다. lParam으로 텍스트를 돌려받기 위한 버퍼 번지를 넘겨준다.

SB_SETTEXT

wParam으로 지정한 파트의 텍스트를 설정한다. lParam으로 문자열을 넘겨준다. wParam이 255일 경우 파트가 하나뿐인 것으로 간주하며 파트의 타입을 OR 연산자로 묶어서 지정할 수 있다.

SB_GETTEXTLENGTH

wParam으로 지정한 파트의 문자열 길이를 구한다. 리턴값의 하위 워드를 읽으면 길이를 구할 수 있다. 리턴값의 상위 워드는 파트의 타입이 설정된다.

SB_SETPARTS

파트를 설정한다. wParam으로 파트의 개수를 주며 lParam에 각 파트의 오른쪽 끝 좌표를 가진 정수형 배열을 준다.

SB_GETPARTS

현재 설정된 파트의 개수와 각 파트의 오른쪽 좌표를 구한다. wParam으로 얻고자 하는 파트의 개수를 지정한다. lParam은 좌표값을 돌려받기 위한 정수형 배열의 포인터를 전달하되 배열의 크기는 wParam과 같아야 한다.

SB_GETBORDERS

상태란의 경계선 두께를 얻는다. lParam으로 크기 3의 정수형 배열을 넘겨주면 첫 번째 요소에 수평 경계선의 두께, 두 번째 요소에 수직 경계선의 두께, 세 번째 요소에 각 파트 사이의 경계선 두께를 채워준다.

SB_SETMINHEIGHT

상태란의 그리기 영역의 최소 높이를 wParam으로 설정한다. 높이는 픽셀단위로 설정하며 이 높이에는 경계선이 제외된다.

SB_SIMPLE

wParam이 TRUE이면 파트 구분을 무시하고 하나의 파트만 가진 상태란을 만들고 FALSE이면 SB_SETPARTS로 구분한 파트를 유지한다.

SB_GETRECT

wParam으로 지정한 파트의 영역을 구한다. lParam으로 RECT 구조체의 포인터를 주면 이 구조체에 영역 좌표를 채워준다.

SB_ISSIMPLE

파트가 하나뿐인 상태란인지 조사한다.

SB_GETICON

wParam으로 전달된 파트의 아이콘의 핸들을 조사한다. 아이콘이 지정되어 있지 않으면 NULL이 리턴된다.

SB_SETICON

파트에 아이콘을 지정한다. wParam으로 파트 번호, lParam으로 아이콘의 핸들을 주되 lParam이 NULL이면 아이콘이 삭제된다. 이렇게 추가된 아이콘은 직접 삭제해 주어야 한다.

SB_GETTIPTEXT

파트의 툴팁을 구한다. wParam의 하위 워드에 파트 번호 상위 워드에 버퍼의 크기를 주고 lParam으로 문자열을 대입받을 버퍼의 포인터를 준다.

SB_SETTIPTEXT

wParam으로 전달된 파트에 툴팁 텍스트를 지정한다. 툴팁을 쓰기 위해서는 SBT_TOOLTIPS 스타일을 가져야 한다. 툴팁은 파트에 아이콘만 있거나 문자열의 일부가 잘려서 보일 때만 나타난다.

SB_GETUNICODEFORMAT

컨트롤의 문자열이 유니코드 포맷이면 0이 아닌 값을 리턴하며 ANSI 포맷이면 0을 리턴한다.

SB_SETBKCOLOR

상태란의 배경색을 지정한다. lParam으로 배경색상을 전달하되 CLR_DEFAULT이면 디폴트 배경색을 사용한다.

 

그럼 예제를 만들어 보자. 상태란을 4등분해서 각 파트에 윈도우의 현재 위치와 크기를 보여주도록 만들어 보았다.

 

Status1

#include <Commctrl.h>

HWND hState;

 

void SetStatusText(HWND hWnd)

{

   RECT wrt;

   char str[128];

 

   GetWindowRect(hWnd, &wrt);

   wsprintf(str, "Left : %d", wrt.left);

   SendMessage(hState, SB_SETTEXT, 0, (LPARAM)str);

   wsprintf(str, "Top : %d", wrt.top);

   SendMessage(hState, SB_SETTEXT, 1, (LPARAM)str);

   wsprintf(str, "Right : %d", wrt.right);

   SendMessage(hState, SB_SETTEXT, 2, (LPARAM)str);

   wsprintf(str, "Bottom : %d", wrt.bottom);

   SendMessage(hState, SB_SETTEXT, 3, (LPARAM)str);

}

 

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

{

   int SBPart[4],i;

 

   switch(iMessage) {

   case WM_CREATE:

      InitCommonControls();

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

      return 0;

   case WM_SIZE:

      SendMessage(hState, WM_SIZE, wParam, lParam);

 

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

          SBPart[i]=LOWORD(lParam)/4*(i+1);

      }

      SendMessage(hState, SB_SETPARTS, 4, (LPARAM)SBPart);

 

      SetStatusText(hWnd);

      return 0;

   case WM_MOVE:

      SetStatusText(hWnd);

      return 0;

   case WM_DESTROY:

      PostQuitMessage(0);

      return 0;

   }

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

}

 

실행시켜 보자. 메인 윈도우의 하단에 상태란이 나타나며 윈도우 크기나 위치가 변경되면 상태란의 정보도 같이 변경된다.

WM_CREATE에서 상태란을 일단 만든다. 윈도우 폭에 따라 각 파트의 폭도 달라져야 하므로 파트를 나누는 일은 WM_SIZE에서 하고 있다. 일단 메인 윈도우의 크기가 변경되면 상태란도 변경된 크기에 맞추어져야 하므로 WM_SIZE 메시지를 그대로 상태란으로 보내준다. 상태란은 기본적으로 부모 윈도우의 하단에 나타나며 WM_SIZE 메시지를 받을 때마다 부모 윈도우의 아래쪽에 작업 영역 폭의 크기로 자동 배치된다. 이때 상태란으로 보내는 WM_SIZE 메시지는 크기와 위치를 재계산하라는 단순한 신호이므로 wParam, lParam은 모두 0으로 준다.

상태란의 위치와 크기를 재계산하도록 한 후 부모 윈도우의 폭을 4등분하여 4개의 파트를 만든다. 각 파트의 오른쪽 끝을 지정하기 위해 SB_SETPARTS 메시지를 보낸다. wParam에는 파트의 개수인 4를 주고 lParam에는 각 파트의 오른쪽 좌표를 담은 정수형 배열을 전달해 주면 된다. 상태란은 lParam으로 전달된 배열로부터 좌표를 꺼내 각 파트의 크기를 조정한다.

특수한 경우로 오른쪽 끝 파트의 폭이 -1로 지정되면 나머지 남은 영역 전체를 채운다. 만약 제일 왼쪽 파트가 나머지 폭을 다 사용하도록 하고 싶다면 직접 부모 윈도우의 폭으로부터 파트의 폭을 계산해 주어야 한다.

상태란에 텍스트를 출력할 때는 SB_SETTEXT 메시지를 보낸다. 예제에서는 이 일을 SetStateText 함수가 수행하고 있다. wParam으로 텍스트를 설정할 파트 번호를 주고 lParam으로 문자열을 주되 wParam에 다음과 같은 파트의 타입을 OR 연산자로 파트 번호와 함께 정해줄 수 있다.

 

타입

설명

SBT_NOBORDERS

경계선을 그리지 않는다.

SBT_OWNERDRAW

부모 윈도우가 텍스트를 직접 그리도록 한다.

SBT_POPOUT

양각의 경계선 안에 텍스트를 출력한다.

SBT_RTLREADING

오른쪽에서 왼쪽으로 문자열을 출력한다.

0

아무 타입을 주지 않으면 음각의 경계선 안에 텍스트를 출력한다.

 

예를 들어 양각의 경계선을 그리려면 다음과 같이 하면 된다.

 

SendMessage(hState, SB_SETTEXT, 1 | SBT_POPOUT, (LPARAM)str);

 

1번 파트만 양각 경계선으로 지정해 보았다. 음각 경계선은 쑥 들어간 모양이지만 양각 경계선은 튀어 나와 있는 모양이 된다.