WM_DRAWITEM

인수

wParam : 이 메시지를 보낸 컨트롤의 ID이다. 메뉴 항목의 경우는 0이 전달된다.

lParam : 그려질 항목에 대한 정보가 담긴 다음 구조체의 포인터이다. 오너는 이 구조체의 내용을 참조하여 컨트롤이나 메뉴 항목을 그린다.

typedef struct tagDRAWITEMSTRUCT {
  UINT      CtlType; 
  UINT      CtlID; 
  UINT      itemID; 
  UINT      itemAction; 
  UINT      itemState; 
  HWND      hwndItem; 
  HDC       hDC; 
  RECT      rcItem; 
  ULONG_PTR itemData; 
} DRAWITEMSTRUCT; 

CtlType : 컨트롤의 타입값

설명

ODT_BUTTON

버튼

ODT_COMBOBOX

콤보 박스

ODT_LISTBOX

리스트 박스

ODT_LISTVIEW

리스트 뷰 컨트롤

ODT_MENU

메뉴 항목

ODT_STATIC

스태틱

ODT_TAB

탭 컨트롤

CtlID : 컨트롤의 ID이며 메뉴 항목은 이 멤버를 사용하지 않는다.

itemID : 메뉴 항목의 ID 또는 리스트 박스나 콤보 박스의 항목 인덱스이다. 리스트 박스나 콤보 박스가 비어 있을 경우 이 값은 -1이 전달되는데 이는 항목이 없더라도 포커스 사각형이라도 그려 포커스를 가지고 있음을 보여 주기 위해서이다.

itemAction : 항목을 그릴 방법을 지정한다.

설명

ODA_DRAWENTIRE

컨트롤 전체를 다 그린다.

ODA_FOCUS

포커스를 얻었거나 잃었다. itemState 값을 참조하여 변경된 포커스를 반영해 주어야 한다.

ODA_SELECT

선택 상태가 바뀌었다. itemState값을 참조하여 선택 상태를 반영해 주어야 한다.

itemState : 항목이 어떻게 보여져야 할 지를 지정하며 다음 값의 조합값으로 표현된다.

플래그

설명

ODS_CHECKED

메뉴 항목이 체크 되었다. 메뉴에서만 이 값이 사용되며 다른 컨트롤에서는 사용되지 않는다.

ODS_COMBOBOXEDIT

콤보 박스의 에디트 컨트롤의 선택 영역에서 그려진다.

ODS_DEFAULT

디폴트 항목이다.

ODS_DISABLED

사용 금지된 항목이다.

ODS_FOCUS

포커스를 가지고 있는 항목이다.

ODS_GRAYED

그레이된 항목이다. 메뉴에서만 이 값이 사용된다.

ODS_HOTLIGHT

98/2000 이상 : 핫 트래킹 항목이다.

ODS_INACTIVE

98/2000 이상 : 비활성화된 항목이다.

ODS_NOACCEL

2000 이상 : 액셀러레이터 표시없이 그려져야 한다.

ODS_NOFOCUSRECT

2000 이상 : 포커스 표시없이 그려져야 한다.

ODS_SELECTED

메뉴 항목이 선택되어 있다.

hwndItem : 컨트롤의 핸들이다. 메뉴의 경우 메뉴 항목을 가진 메뉴 핸들이 된다.

hDC : 그리기에 사용할 DC 핸들이며 반드시 이 DC를 사용하여 그려져야 한다.

rcItem : 컨트롤이 그려져야할 사각 영역을 지정한다. 오너는 이 영역 안에서만 그리기를 해야 하며 이 영역을 벗어난 출력은 잘려 나간다. 단, 메뉴 항목의 경우는 잘려 나가지 않으므로 이 영역 외부에 그리지 않도록 주의해야 한다.

itemData : 메뉴 항목에 응용 프로그램이 정의한 항목 데이터이다. 리스트 박스, 콤보 박스의 경우 LB(CB) _SETITMEDATA 메시지로 항목에 추가한 항목 데이터이다. 버튼이나 스택 컨트롤은 항목 데이터를 가지지 않으므로 이 멤버는 항상 0이다.

설명

오너 드로우 버튼, 리스트 박스, 콤보 박스, 메뉴가 그려져야 할 필요가 있을 때 오너 윈도우에게 이 메시지가 전달된다. 오너는 lParam으로 전달된 컨트롤의 종류와 상태에 따라 컨트롤을 적절히 그려 주어야 할 책임이 있다. 만약 오너 드로우 리스트 박스를 가진 윈도우가 이 메시지를 처리하지 않고 DefWindowProc으로 보내면 포커스 사각형만 그려진다.

lParam의 DRAWITEMSTRUCT에는 항목 그리기에 사용할 DC의 핸들과 출력 영역이 전달되는데 이 정보를 참조하여 그리되 DC는 반드시 원래 상태대로 유지해 주어야 한다. DC에 커스텀 펜이나 브러시를 선택해 사용할 수 있지만 그 이전 객체를 반드시 복구시켜 주어야 한다.

리턴

이 메시지를 처리했으면 TRUE를 리턴해야 한다.

예제

예제 1

다음 예제는 고정 높이의 오너 드로우 리스트 박스를 그린다.

HWND hList;
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	LPMEASUREITEMSTRUCT lpmis;
	LPDRAWITEMSTRUCT lpdis;
	HBRUSH bkBrush, hBrush, OldBrush;

	switch(iMessage) {
	case WM_CREATE:
		hList=CreateWindow("listbox",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER |
			WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWFIXED,
			10,10,110,200,hWnd,(HMENU)0,g_hInst,NULL);
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)RGB(255,0,0));
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)RGB(0,255,0));
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)RGB(0,0,255));
		return 0;
	case WM_MEASUREITEM:
		lpmis=(LPMEASUREITEMSTRUCT)lParam;
		lpmis->itemHeight=30;
		return TRUE;
	case WM_DRAWITEM:
		lpdis=(LPDRAWITEMSTRUCT)lParam;

		if (lpdis->itemState & ODS_SELECTED) {
			bkBrush=CreateSolidBrush(RGB(255,255,0));
		}
		else {
			bkBrush=CreateSolidBrush(RGB(255,255,255));
		}
		FillRect(lpdis->hDC, &lpdis->rcItem, bkBrush);

		if (lpdis->itemState & ODS_FOCUS) {
			DrawFocusRect(lpdis->hDC,&lpdis->rcItem);
		}

		hBrush=CreateSolidBrush(lpdis->itemData);
		OldBrush=(HBRUSH)SelectObject(lpdis->hDC,hBrush);
		Rectangle(lpdis->hDC,lpdis->rcItem.left+5,lpdis->rcItem.top+5,
			lpdis->rcItem.right-5,lpdis->rcItem.bottom-5);
		SelectObject(lpdis->hDC,OldBrush);
		DeleteObject(hBrush);
		DeleteObject(bkBrush);
		return TRUE;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

리스트 박스에는 세가지 색상의 사각형이 등록되어 있으며 색상값을 각 항목의 항목 데이터에 기억시켜 주었다. LBS_OWNERDRAWFIXED 스타일을 지정했으므로 리스트 박스의 각 항목들은 모두 높이가 같으며 이 높이는 WM_MEASUREITEM 메시지에서 30픽셀로 대입해 주었다. 각 항목을 그려야 할 때 리스트 박스는 부모 윈도우에게 WM_DRAWITEM 메시지를 보내주며 부모 윈도우는 이 메시지의 lParam으로 전달된 DRAWITEMSTRUCTURE를 참고하여 항목을 그린다.

항목이 선택되어 있으면 노란색 배경을 그리도록 했으며 포커스를 가지고 있으면 포커스 사각형도 같이 그려 주었다. 그리기가 끝나면 DC는 반드시 원래대로 돌려 놓아야 한다.

예제 2

다음 예제는 가변 높이를 가지는 오너 드로우 리스트 박스를 그린다.

HWND hList;
struct tagItem
{
	COLORREF col;
	int height;
} Items[3]={
	{RGB(255,0,0),20},
	{RGB(0,255,0),30},
	{RGB(0,0,255),40},
};

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	LPMEASUREITEMSTRUCT lpmis;
	LPDRAWITEMSTRUCT lpdis;
	HBRUSH bkBrush, hBrush, OldBrush;

	switch(iMessage) {
	case WM_CREATE:
		hList=CreateWindow("listbox",NULL,WS_CHILD | WS_VISIBLE | WS_BORDER |
			WS_VSCROLL | LBS_NOTIFY | LBS_OWNERDRAWVARIABLE,
			10,10,110,200,hWnd,(HMENU)0,g_hInst,NULL);
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)&Items[0]);
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)&Items[1]);
		SendMessage(hList,LB_ADDSTRING,0,(LPARAM)&Items[2]);
		return 0;
	case WM_MEASUREITEM:
		lpmis=(LPMEASUREITEMSTRUCT)lParam;
		lpmis->itemHeight=((tagItem *)lpmis->itemData)->height;
		return TRUE;
	case WM_DRAWITEM:
		lpdis=(LPDRAWITEMSTRUCT)lParam;

		if (lpdis->itemState & ODS_SELECTED) {
			bkBrush=CreateSolidBrush(RGB(255,255,0));
		}
		else {
			bkBrush=CreateSolidBrush(RGB(255,255,255));
		}
		FillRect(lpdis->hDC, &lpdis->rcItem, bkBrush);

		if (lpdis->itemState & ODS_FOCUS) {
			DrawFocusRect(lpdis->hDC,&lpdis->rcItem);
		}

		hBrush=CreateSolidBrush(((tagItem *)lpdis->itemData)->col);
		OldBrush=(HBRUSH)SelectObject(lpdis->hDC,hBrush);
		Rectangle(lpdis->hDC,lpdis->rcItem.left+5,lpdis->rcItem.top+5,
			lpdis->rcItem.right-5,lpdis->rcItem.bottom-5);
		SelectObject(lpdis->hDC,OldBrush);
		DeleteObject(hBrush);
		DeleteObject(bkBrush);
		return TRUE;
	case WM_PAINT:
		hdc=BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	}
	return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

각 항목은 자신의 높이와 색상에 대한 정보를 항목 데이터로 정의하고 있으며 WM_MEASUREITEM 메시지를 받았을 때 항목의 높이를 조사해 주었고 WM_DRAWITEM에서는 전달된 그리기 영역에 항목을 그린다.

플랫폼

95이상

참조

 


written by http://www.winapi.co.kr