콤보 상자를 하위 클래스로 분류하는 방법
이 항목에서는 콤보 상자를 하위 클래스로 분류하는 방법을 보여 줍니다. C++ 예 애플리케이션은 두 개의 콤보 상자가 포함된 도구 모음 창을 만듭니다. 도구 모음 창은 콤보 상자 내에서 편집 컨트롤을 하위 클래스로 분류함으로써 무시될 TAB, ENTER 및 ESC 키를 가로챕니다.
알아야 하는 작업
기술
필수 구성 요소
- C/C++
- Windows 사용자 인터페이스 프로그래밍
지침
WM_CREATE 메시지 처리
애플리케이션은 WM_CREATE 메시지를 처리하여 두 개의 콤보 상자 컨트롤을 자식 창으로 만듭니다.
// Create two combo box child windows.
dwBaseUnits = GetDialogBaseUnits();
hwndCombo1 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(6 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, NULL, NULL);
hwndCombo2 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(112 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, hInst, NULL);
그런 다음 애플리케이션은 단순 및 드롭다운 콤보 상자에 대한 문자 입력을 받기 때문에 각 콤보 상자의 편집 컨트롤(선택 필드)을 하위 클래스로 분류합니다. 마지막으로 ChildWindowFromPoint 함수를 호출하여 각 편집 컨트롤에 대한 핸들을 검색합니다.
편집 컨트롤의 하위 클래스를 만들기 위해 애플리케이션은 SetWindowLong 함수를 호출하여 클래스 창 프로시저에 대한 포인터를 애플리케이션 정의 SubClassProc 함수에 대한 포인터로 바꿉니다. 원래 창 프로시저에 대한 포인터는 전역 변수 lpfnEditWndProc에 저장됩니다.
SubClassProc는 TAB, ENTER 및 ESC 키를 가로채고 애플리케이션 정의 메시지(WM_TAB, WM_ESC 및 WM_ENTER)를 전송하여 도구 모음 창에 알립니다. SubClassProc는 CallWindowProc 함수를 사용하여 대부분의 메시지를 원래 창 프로시저인 lpfnEditWndProc에 전달합니다.
// Get the edit window handle to each combo box.
pt.x = 1;
pt.y = 1;
hwndEdit1 = ChildWindowFromPoint(hwndCombo1, pt);
hwndEdit2 = ChildWindowFromPoint(hwndCombo2, pt);
// Change the window procedure for both edit windows
// to the subclass procedure.
lpfnEditWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit1,
GWLP_WNDPROC, (LONG_PTR) SubClassProc);
SetWindowLongPtr(hwndEdit2, GWLP_WNDPROC, (LONG_PTR) SubClassProc);
WM_SETFOCUS 메시지 처리
도구 모음 창은 입력 포커스를 받으면 즉시 도구 모음의 첫 번째 콤보 상자에 포커스를 설정합니다. 이를 위해 예에서는 WM_SETFOCUS 메시지에 대한 응답으로 SetFocus 함수를 호출합니다.
case WM_SETFOCUS:
SetFocus(hwndCombo1);
break;
애플리케이션 정의 메시지 처리
SubClassProc 함수는 사용자가 콤보 상자에서 TAB, ENTER 또는 ESC 키를 누를 때 애플리케이션 정의 메시지를 도구 모음 창으로 보냅니다. WM_TAB 메시지는 TAB 키로, WM_ESC 메시지는 ESC 키로, WM_ENTER 메시지는 ENTER 키로 전송됩니다.
이 예에서는 도구 모음의 다음 콤보 상자에 포커스를 설정하여 WM_TAB 메시지를 처리합니다. 기본 애플리케이션 창에 포커스를 설정하여 WM_ESC 메시지를 처리합니다.
case WM_TAB:
if (GetFocus() == hwndEdit1)
SetFocus(hwndCombo2);
else
SetFocus(hwndCombo1);
break;
case WM_ESC:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
// Clear the current selection.
SendMessage(hwndCombo, CB_SETCURSEL,
(WPARAM) (-1), 0);
// Set the focus to the main window.
SetFocus(hwndMain);
break;
WM_ENTER 메시지에 대한 응답으로 예는 콤보 상자의 현재 선택이 유효한지 확인한 다음 기본 애플리케이션 창에 포커스를 설정합니다. 콤보 상자에 현재 선택 항목이 없는 경우 이 예에서는 CB_FINDSTRINGEXACT 메시지를 사용하여 선택 필드의 콘텐츠와 일치하는 목록 항목을 검색합니다. 일치하는 항목이 있는 경우 이 예에서는 현재 선택 항목을 설정합니다. 그렇지 않으면 새 목록 항목을 추가합니다.
case WM_ENTER:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
SetFocus(hwndMain);
// If there is no current selection, set one.
if (SendMessage(hwndCombo, CB_GETCURSEL, 0, 0)
== CB_ERR)
{
if (SendMessage(hwndCombo, WM_GETTEXT,
sizeof(achTemp), (LPARAM) achTemp) == 0)
break; // Empty selection field
dwIndex = SendMessage(hwndCombo,
CB_FINDSTRINGEXACT, (WPARAM) (-1),
(LPARAM) achTemp);
// Add the string, if necessary, and select it.
if (dwIndex == CB_ERR)
dwIndex = SendMessage(hwndCombo, CB_ADDSTRING,
0, (LPARAM) achTemp);
if (dwIndex != CB_ERR)
SendMessage(hwndCombo, CB_SETCURSEL,
dwIndex, 0);
}
break;
// .
// . Process additional messages.
// .
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
전체 예제
다음은 도구 모음에 대한 창 프로시저와 두 콤보 상자에 대한 하위 클래스 프로시저입니다.
#define WM_TAB (WM_USER)
#define WM_ESC (WM_USER + 1)
#define WM_ENTER (WM_USER + 2)
// Global variables
HWND hwndMain;
WNDPROC lpfnEditWndProc; // Original wndproc for the combo box
// Prototypes
LRESULT CALLBACK SubClassProc( HWND, UINT, WPARAM, LPARAM );
/********************************************************
FUNCTION: ToolbarWindowProc
PURPOSE: Window procedure for the toolbar window
*********************************************************/
LRESULT CALLBACK ToolbarWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
static HWND hwndEdit1;
static HWND hwndEdit2;
static HWND hwndCombo1;
static HWND hwndCombo2;
POINT pt;
DWORD dwBaseUnits;
HWND hwndCombo;
DWORD dwIndex;
char achTemp[256]; // Temporary buffer
switch (msg)
{
case WM_CREATE:
// Create two combo box child windows.
dwBaseUnits = GetDialogBaseUnits();
hwndCombo1 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(6 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, NULL, NULL);
hwndCombo2 = CreateWindow(L"COMBOBOX", L"",
CBS_DROPDOWN | WS_CHILD | WS_VISIBLE,
(112 * LOWORD(dwBaseUnits)) / 4,
(2 * HIWORD(dwBaseUnits)) / 8,
(100 * LOWORD(dwBaseUnits)) / 4,
(50 * HIWORD(dwBaseUnits)) / 8,
hwnd, NULL, hInst, NULL);
// Get the edit window handle to each combo box.
pt.x = 1;
pt.y = 1;
hwndEdit1 = ChildWindowFromPoint(hwndCombo1, pt);
hwndEdit2 = ChildWindowFromPoint(hwndCombo2, pt);
// Change the window procedure for both edit windows
// to the subclass procedure.
lpfnEditWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit1,
GWLP_WNDPROC, (LONG_PTR) SubClassProc);
SetWindowLongPtr(hwndEdit2, GWLP_WNDPROC, (LONG_PTR) SubClassProc);
break;
case WM_SETFOCUS:
SetFocus(hwndCombo1);
break;
case WM_TAB:
if (GetFocus() == hwndEdit1)
SetFocus(hwndCombo2);
else
SetFocus(hwndCombo1);
break;
case WM_ESC:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
// Clear the current selection.
SendMessage(hwndCombo, CB_SETCURSEL,
(WPARAM) (-1), 0);
// Set the focus to the main window.
SetFocus(hwndMain);
break;
case WM_ENTER:
hwndCombo = GetFocus() == hwndEdit1 ? hwndCombo1 : hwndCombo2;
SetFocus(hwndMain);
// If there is no current selection, set one.
if (SendMessage(hwndCombo, CB_GETCURSEL, 0, 0)
== CB_ERR)
{
if (SendMessage(hwndCombo, WM_GETTEXT,
sizeof(achTemp), (LPARAM) achTemp) == 0)
break; // Empty selection field
dwIndex = SendMessage(hwndCombo,
CB_FINDSTRINGEXACT, (WPARAM) (-1),
(LPARAM) achTemp);
// Add the string, if necessary, and select it.
if (dwIndex == CB_ERR)
dwIndex = SendMessage(hwndCombo, CB_ADDSTRING,
0, (LPARAM) achTemp);
if (dwIndex != CB_ERR)
SendMessage(hwndCombo, CB_SETCURSEL,
dwIndex, 0);
}
break;
// .
// . Process additional messages.
// .
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/********************************************************
FUNCTION: SubClassProc
PURPOSE: Process TAB and ESCAPE keys, and pass all
other messages to the class window
procedure.
*********************************************************/
LRESULT CALLBACK SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_TAB:
SendMessage(hwndMain, WM_TAB, 0, 0);
return 0;
case VK_ESCAPE:
SendMessage(hwndMain, WM_ESC, 0, 0);
return 0;
case VK_RETURN:
SendMessage(hwndMain, WM_ENTER, 0, 0);
return 0;
}
break;
case WM_KEYUP:
case WM_CHAR:
switch (wParam)
{
case VK_TAB:
case VK_ESCAPE:
case VK_RETURN:
return 0;
}
}
// Call the original window procedure for default processing.
return CallWindowProc(lpfnEditWndProc, hwnd, msg, wParam, lParam);
}
관련 항목