소유자가 그린 콤보 상자를 만드는 방법
이 항목에서는 소유자가 그린 콤보 상자를 사용하는 방법을 보여 줍니다. C++ 코드 예제에서는 소유자가 그린 드롭다운 목록 상자를 사용하여 각각 비트맵과 이름으로 표시되는 4개의 음식 그룹을 표시합니다. 음식 그룹을 선택하면 해당 그룹의 음식이 목록에 표시됩니다.
대화 상자에는 목록 상자(IDLIST)와 두 개의 단추인 확인(IDOK) 및 취소(IDCANCEL)도 포함됩니다. IDOK 및 IDCANCEL 상수는 SDK 헤더 파일에 의해 정의됩니다. 상수 IDLIST는 컨트롤 식별자 IDCOMBO와 마찬가지로 애플리케이션의 헤더 파일에 정의됩니다. 이러한 대화 상자에 대한 자세한 내용은 대화 상자를 참조하세요.
알아야 하는 작업
기술
필수 구성 요소
- C/C++
- Windows 사용자 인터페이스 프로그래밍
지침
1단계: 소유자가 그린 대화 상자 만들기
이 코드 예제에서는 DialogBox 함수를 사용하여 모달 대화 상자를 만듭니다. IDD_SQMEAL 대화 상자 템플릿은 콤보 상자의 창 스타일, 단추 및 컨트롤 식별자를 정의합니다. 이 예제의 콤보 상자는 CBS_DROPDOWNLIST, CBS_OWNERDRAWFIXED, CBS_SORT, CBS_HASSTRINGS, WS_VSCROLL 및 WS_TABSTOP 스타일을 사용합니다.
DialogBox(hInst, MAKEINTRESOURCE(IDD_SQMEAL),
hWnd, FoodDlgProc);
2단계: 대화 상자에서 WM_INITDIALOG 및 WM_DESTROY 메시지를 처리합니다.
대화 상자에서 콤보 상자를 사용하는 경우 일반적으로 콤보 상자를 초기화하여 WM_INITDIALOG 메시지에 응답합니다. 애플리케이션은 소유자가 그린 콤보 상자에 사용되는 비트맵을 로드한 다음 애플리케이션 정의 InitGroupList
함수를 호출하여 콤보 상자를 초기화합니다. 또한 콤보 상자에서 첫 번째 목록 항목을 선택한 다음 애플리케이션 정의 InitFoodList
함수를 호출하여 목록 상자를 초기화합니다.
이 예제에서 소유자가 그린 콤보 상자는 4개의 음식 그룹 각각에 대한 이름이 포함된 드롭다운 목록 상자입니다.
InitGroupList
는 각 음식 그룹의 이름을 추가하고 CB_SETITEMDATA 메시지를 사용하여 음식 그룹을 식별하는 각 목록 항목과 비트맵 핸들을 연결합니다.
예제의 목록 상자에는 선택한 음식 그룹의 음식 이름이 포함됩니다. InitFoodList는 목록 상자의 콘텐츠를 초기화한 다음 현재 음식 그룹 드롭다운 목록 상자에 현재 음식 선택 항목의 이름을 추가합니다.
case WM_INITDIALOG:
// Call an application-defined function to load bitmap resources.
if (!LoadIconBitmaps())
{
EndDialog(hDlg, -1);
break;
}
// Initialize the food groups combo box and select the first item.
InitGroupList(hDlg);
SendDlgItemMessage(hDlg, IDCOMBO, CB_SETCURSEL, 0, 0);
// Initialize the food list box and select the first item.
InitFoodList(hDlg);
SendDlgItemMessage(hDlg, IDLIST, LB_SETCURSEL, 0, 0);
return (INT_PTR)TRUE;
WM_DESTROY 메시지를 받으면 애플리케이션은 소유자가 그린 콤보 상자에서 비트맵을 삭제합니다.
case WM_DESTROY:
// Call the application-defined function to free the bitmap resources.
DeleteIconBitmaps();
break;
3단계: WM_MEASUREITEM 메시지 처리
소유자가 그린 콤보 상자는 애플리케이션이 각 목록 항목의 크기를 설정할 수 있도록 부모 창 또는 대화 상자 프로시저에 WM_MEASUREITEM 메시지를 보냅니다. 예제 콤보 상자에는 CBS_OWNERDRAWFIXED 스타일이 있으므로 시스템은 WM_MEASUREITEM 메시지를 한 번만 보냅니다. CBS_OWNERDRAWVARIABLE 스타일이 있는 콤보 상자는 각 목록 항목에 대한 WM_MEASUREITEM 메시지를 보냅니다.
lParam 매개 변수는 컨트롤 및 목록 항목을 식별하는 MEASUREITEMSTRUCT 구조체에 대한 포인터입니다. 또한 목록 항목의 기본 차원도 포함합니다. 이 예제에서는 itemHeight 구조체 멤버를 수정하여 목록 항목이 음식 그룹 비트맵을 수용할 수 있을 만큼 충분히 높은지 확인합니다.
case WM_MEASUREITEM:
{
// Set the height of the items in the food groups combo box.
LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
if (lpmis->itemHeight < CY_BITMAP + 2)
lpmis->itemHeight = CY_BITMAP + 2;
break;
}
4단계: WM_DRAWITEM 메시지 처리
소유자가 그린 콤보 상자는 애플리케이션이 목록 항목을 다시 그려야 할 때마다 부모 창 또는 대화 상자 프로시저에 WM_DRAWITEM 메시지를 보냅니다. lParam 매개 변수는 컨트롤 및 목록 항목을 식별하는 DRAWITEMSTRUCT 구조체에 대한 포인터입니다. 또한 항목을 그리는 데 필요한 정보도 포함합니다.
예제 애플리케이션은 목록 항목 텍스트 및 음식 그룹과 연결된 비트맵을 표시합니다. 항목에 포커스가 있는 경우 포커스 사각형도 그립니다. 텍스트를 표시하기 전에 예제에서는 선택한 항목에 따라 전경색과 배경색을 설정합니다. 콤보 상자에는 CBS_HASSTRINGS 스타일이 있으므로 콤보 상자는 CB_GETLBTEXT 메시지를 사용하여 검색할 수 있는 각 목록 항목의 텍스트를 유지 관리합니다.
목록 항목에 사용되는 비트맵은 음식 그룹에 따라 달라집니다.
InitGroupList
는 CB_SETITEMDATA 메시지를 사용하여 비트맵 핸들을 각 목록 항목과 연결합니다. 창 프로시저는 DRAWITEMSTRUCT 구조체의 itemData 멤버에서 비트맵 핸들을 검색합니다. 시스템은 각 음식 그룹 기호에 대해 두 개의 비트맵을 사용합니다. 즉, SRCAND 래스터 조작이 있는 단색 비트맵을 사용하여 이미지 뒤의 불규칙한 영역을 지우고 SRCPAINT 래스터 조작이 있는 색상 비트맵을 사용하여 이미지를 그립니다.
case WM_DRAWITEM:
{
COLORREF clrBackground;
COLORREF clrForeground;
TEXTMETRIC tm;
int x;
int y;
HRESULT hr;
size_t cch;
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
if (lpdis->itemID == -1) // Empty item)
break;
// Get the food icon from the item data.
hbmIcon = (HBITMAP) lpdis->itemData;
// The colors depend on whether the item is selected.
clrForeground = SetTextColor(lpdis->hDC,
GetSysColor(lpdis->itemState & ODS_SELECTED ?
COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
clrBackground = SetBkColor(lpdis->hDC,
GetSysColor(lpdis->itemState & ODS_SELECTED ?
COLOR_HIGHLIGHT : COLOR_WINDOW));
// Calculate the vertical and horizontal position.
GetTextMetrics(lpdis->hDC, &tm);
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
x = LOWORD(GetDialogBaseUnits()) / 4;
// Get and display the text for the list item.
SendMessage(lpdis->hwndItem, CB_GETLBTEXT,
lpdis->itemID, (LPARAM) achTemp);
hr = StringCchLength(achTemp, 256, &cch);
if (FAILED(hr))
{
// TODO: Write error handler.
}
ExtTextOut(lpdis->hDC, CX_BITMAP + 2 * x, y,
ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
achTemp, (UINT)cch, NULL);
// Restore the previous colors.
SetTextColor(lpdis->hDC, clrForeground);
SetBkColor(lpdis->hDC, clrBackground);
// Draw the food icon for the item.
HDC hdc = CreateCompatibleDC(lpdis->hDC);
if (hdc == NULL)
break;
SelectObject(hdc, hbmMask);
BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCAND);
SelectObject(hdc, hbmIcon);
BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCPAINT);
DeleteDC(hdc);
// If the item has the focus, draw the focus rectangle.
if (lpdis->itemState & ODS_FOCUS)
DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
break;
}
5단계: WM_COMMAND 메시지를 처리합니다.
이벤트가 대화 상자 컨트롤에서 발생하면 컨트롤은 WM_COMMAND 메시지를 통해 대화 상자 프로시저를 알 수 있습니다. 이 예제에서는 콤보 상자, 목록 상자 및 확인 단추에서 알림 메시지를 처리합니다. 컨트롤 식별자는 wParam의 하위 단어에 있고 알림 코드는 wParam의 상위 단어에 있습니다.
컨트롤 식별자가 IDCOMBO이면 콤보 상자에서 이벤트가 발생한 것입니다. 이에 대한 응답으로 대화 상자 프로시저는 CBN_SELENDOK를 제외한 다른 모든 콤보 상자 이벤트를 무시합니다. 이 이벤트는 선택되고 드롭다운 목록 상자가 닫혔으며 변경 내용을 수락해야 함을 나타냅니다. 대화 상자 프로시저는 InitFoodList
를 호출하여 목록 상자의 콘텐츠를 재설정하고 드롭다운 목록 상자에 현재 선택 항목의 이름을 추가합니다.
컨트롤 식별자가 IDLIST이면 목록 상자에서 이벤트가 발생한 것입니다. 이로 인해 대화 상자 프로시저는 사용자가 목록 항목을 두 번 클릭했음을 나타내는 LBN_DBLCLK를 제외한 모든 목록 상자 이벤트를 무시합니다. 이 이벤트는 확인 단추를 선택하는 것과 동일한 방식으로 처리됩니다.
컨트롤 식별자가 IDOK이면 사용자가 확인 단추를 선택한 것입니다. 이에 대한 응답으로 대화 상자 프로시저는 선택한 음식의 이름을 애플리케이션의 여러 줄 편집 컨트롤에 삽입한 다음 EndDialog 함수를 호출하여 대화 상자를 닫습니다.
컨트롤 식별자가 IDCANCEL인 경우 사용자가 취소 단추를 클릭한 것입니다. 이에 대한 응답으로 대화 상자 프로시저는 EndDialog를 호출하여 대화 상자를 닫습니다.
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCOMBO:
if (HIWORD(wParam) == CBN_SELENDOK)
{
InitFoodList(hDlg);
SendDlgItemMessage(hDlg, IDLIST,
LB_SETCURSEL, 0, 0);
}
break;
case IDLIST:
if (HIWORD(wParam) != LBN_DBLCLK)
break;
// For a double-click, process the OK case.
case IDOK:
// Get the text for the selected list item.
hwnd = GetDlgItem(hDlg, IDLIST);
// Here it is assumed the text can fit into achTemp.
// If there is doubt, call LB_GETTEXTLENGTH first.
SendMessage(hwnd, LB_GETTEXT,
SendMessage(hwnd, LB_GETCURSEL, 0, 0),
(LPARAM) achTemp);
// TODO: Do something with the selected text.
EndDialog(hDlg, 0);
break;
case IDCANCEL:
hwnd = GetDlgItem(hDlg, IDCOMBO);
if (SendMessage(hwnd, CB_GETDROPPEDSTATE, 0, 0))
SendMessage(hwnd, CB_SHOWDROPDOWN, FALSE, 0);
else EndDialog(hDlg, 0);
}
break;
전체 예제
다음은 대화 상자 프로시저와 Square Meal 대화 상자의 지원 함수입니다.
#define ID_BREAD 0
#define ID_DAIRY 1
#define ID_FRUIT 2
#define ID_MEAT 3
#define CX_BITMAP 24
#define CY_BITMAP 24
HBITMAP hbmBread;
HBITMAP hbmDairy;
HBITMAP hbmMeat;
HBITMAP hbmFruit;
HBITMAP hbmMask;
HBITMAP hbmIcon;
// Message handler for Square Meal dialog box.
INT_PTR CALLBACK FoodDlgProc(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
TCHAR achTemp[256];
HWND hwnd;
switch (message)
{
case WM_INITDIALOG:
// Call an application-defined function to load bitmap resources.
if (!LoadIconBitmaps())
{
EndDialog(hDlg, -1);
break;
}
// Initialize the food groups combo box and select the first item.
InitGroupList(hDlg);
SendDlgItemMessage(hDlg, IDCOMBO, CB_SETCURSEL, 0, 0);
// Initialize the food list box and select the first item.
InitFoodList(hDlg);
SendDlgItemMessage(hDlg, IDLIST, LB_SETCURSEL, 0, 0);
return (INT_PTR)TRUE;
case WM_MEASUREITEM:
{
// Set the height of the items in the food groups combo box.
LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT) lParam;
if (lpmis->itemHeight < CY_BITMAP + 2)
lpmis->itemHeight = CY_BITMAP + 2;
break;
}
case WM_DRAWITEM:
{
COLORREF clrBackground;
COLORREF clrForeground;
TEXTMETRIC tm;
int x;
int y;
HRESULT hr;
size_t cch;
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT) lParam;
if (lpdis->itemID == -1) // Empty item)
break;
// Get the food icon from the item data.
hbmIcon = (HBITMAP) lpdis->itemData;
// The colors depend on whether the item is selected.
clrForeground = SetTextColor(lpdis->hDC,
GetSysColor(lpdis->itemState & ODS_SELECTED ?
COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
clrBackground = SetBkColor(lpdis->hDC,
GetSysColor(lpdis->itemState & ODS_SELECTED ?
COLOR_HIGHLIGHT : COLOR_WINDOW));
// Calculate the vertical and horizontal position.
GetTextMetrics(lpdis->hDC, &tm);
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
x = LOWORD(GetDialogBaseUnits()) / 4;
// Get and display the text for the list item.
SendMessage(lpdis->hwndItem, CB_GETLBTEXT,
lpdis->itemID, (LPARAM) achTemp);
hr = StringCchLength(achTemp, 256, &cch);
if (FAILED(hr))
{
// TODO: Write error handler.
}
ExtTextOut(lpdis->hDC, CX_BITMAP + 2 * x, y,
ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
achTemp, (UINT)cch, NULL);
// Restore the previous colors.
SetTextColor(lpdis->hDC, clrForeground);
SetBkColor(lpdis->hDC, clrBackground);
// Draw the food icon for the item.
HDC hdc = CreateCompatibleDC(lpdis->hDC);
if (hdc == NULL)
break;
SelectObject(hdc, hbmMask);
BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCAND);
SelectObject(hdc, hbmIcon);
BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCPAINT);
DeleteDC(hdc);
// If the item has the focus, draw the focus rectangle.
if (lpdis->itemState & ODS_FOCUS)
DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
break;
}
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDCOMBO:
if (HIWORD(wParam) == CBN_SELENDOK)
{
InitFoodList(hDlg);
SendDlgItemMessage(hDlg, IDLIST,
LB_SETCURSEL, 0, 0);
}
break;
case IDLIST:
if (HIWORD(wParam) != LBN_DBLCLK)
break;
// For a double-click, process the OK case.
case IDOK:
// Get the text for the selected list item.
hwnd = GetDlgItem(hDlg, IDLIST);
// Here it is assumed the text can fit into achTemp.
// If there is doubt, call LB_GETTEXTLENGTH first.
SendMessage(hwnd, LB_GETTEXT,
SendMessage(hwnd, LB_GETCURSEL, 0, 0),
(LPARAM) achTemp);
// TODO: Do something with the selected text.
EndDialog(hDlg, 0);
break;
case IDCANCEL:
hwnd = GetDlgItem(hDlg, IDCOMBO);
if (SendMessage(hwnd, CB_GETDROPPEDSTATE, 0, 0))
SendMessage(hwnd, CB_SHOWDROPDOWN, FALSE, 0);
else EndDialog(hDlg, 0);
}
break;
case WM_DESTROY:
// Call the application-defined function to free the bitmap resources.
DeleteIconBitmaps();
break;
}
return (INT_PTR)FALSE;
}
// Loads string resources and adds them as items to the drop-down list of
// the food groups combo box. The bitmap handle of each item's icon is
// stored as item data for easy access when the item needs to be drawn.
//
void InitGroupList(HWND hDlg)
{
TCHAR achTemp[256];
DWORD dwIndex;
// Get the handle of the food groups combo box.
HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);
LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp)/sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM) achTemp);
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM) hbmBread);
LoadString(hInst, IDS_DAIRY, achTemp, sizeof(achTemp)/sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM) achTemp);
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM) hbmDairy);
LoadString(hInst, IDS_FRUIT, achTemp, sizeof(achTemp)/sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM) achTemp);
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM) hbmFruit);
LoadString(hInst, IDS_MEAT, achTemp, sizeof(achTemp)/sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM) achTemp);
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM) hbmMeat);
return;
}
// Fills the food list based on the selected item in the food groups
// combo box.
void InitFoodList(HWND hDlg)
{
TCHAR achTemp[256];
HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);
HWND hwndFoodList = GetDlgItem(hDlg, IDLIST);
// Clear the list contents.
SendMessage(hwndFoodList, LB_RESETCONTENT, 0, 0);
// Find out which food group is selected.
int idFoodGroup = SendMessage(hwndGroupsBox, CB_GETCURSEL, 0, 0);
switch (idFoodGroup)
{
case ID_BREAD:
LoadString(hInst, IDS_OAT, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_WHEAT, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_RYE, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
break;
case ID_DAIRY:
LoadString(hInst, IDS_CHEDDAR, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_MILK, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_PROCESSED, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_SWISS, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
break;
case ID_FRUIT:
LoadString(hInst, IDS_APPLES, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_BANANAS, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_ORANGES, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
break;
case ID_MEAT:
LoadString(hInst, IDS_BEEF, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_CHICKEN, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
LoadString(hInst, IDS_PORK, achTemp, sizeof(achTemp)/sizeof(TCHAR));
SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM) achTemp);
break;
default:
break;
}
return;
}
// Loads the food icon bitmaps from the application resources.
//
BOOL LoadIconBitmaps(void)
{
hbmBread = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD));
if (hbmBread != NULL)
hbmDairy = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_DAIRY));
if (hbmDairy != NULL)
hbmMeat = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_MEAT));
if (hbmMeat != NULL)
hbmFruit = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_FRUIT));
if (hbmFruit != NULL)
hbmMask = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_MASK));
if (hbmMask != NULL)
return TRUE;
return FALSE;
}
// Frees the icon bitmps.
//
void DeleteIconBitmaps(void)
{
FreeResource(reinterpret_cast<HGLOBAL>(hbmBread));
FreeResource(reinterpret_cast<HGLOBAL>(hbmDairy));
FreeResource(reinterpret_cast<HGLOBAL>(hbmMeat));
FreeResource(reinterpret_cast<HGLOBAL>(hbmFruit));
FreeResource(reinterpret_cast<HGLOBAL>(hbmMask));
}
관련 항목