사용자 지정 컨트롤

이 섹션에는 애플리케이션 정의 컨트롤 또는 사용자 지정 컨트롤에 대한 정보가 포함되어 있습니다.

다음 항목을 다룹니다.

소유자가 그린 컨트롤 만들기

소유자가 그린 스타일 플래그를 사용하여 단추, 메뉴, 정적 텍스트 컨트롤, 목록 상자 및 콤보 상자를 만들 수 있습니다. 컨트롤에 소유자가 그린 스타일이 있는 경우 시스템은 사용자가 단추를 선택한 시기를 감지하고 단추의 소유자에게 이벤트를 알리는 등의 작업을 수행하여 컨트롤과 사용자의 상호 작용을 평소와 같이 처리합니다. 그러나 컨트롤이 소유자가 그린 것이므로 컨트롤의 부모 창은 컨트롤의 시각적 모양을 담당합니다. 부모 창은 컨트롤을 그려야 할 때마다 메시지를 받습니다.

단추 및 정적 텍스트 컨트롤의 경우 소유자가 그린 스타일은 시스템이 전체 컨트롤을 그리는 방법에 영향을 줍니다. 목록 상자 및 콤보 상자의 경우 부모 창은 컨트롤 내의 항목을 그리고 컨트롤은 자체 윤곽선을 그립니다. 예를 들어 애플리케이션은 목록의 각 항목 옆에 작은 비트맵을 표시하도록 목록 상자를 사용자 지정할 수 있습니다.

다음 예제 코드는 소유자가 그린 정적 텍스트 컨트롤을 만드는 방법을 보여 줍니다. 유니코드가 정의되어 있다고 가정합니다.

// g_myStatic is a global HWND variable.
g_myStatic = CreateWindowEx(0, L"STATIC", L"Some static text", 
            WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, 
            25, 125, 150, 20, hDlg, 0, 0, 0);

다음 예제에서는 이전 예제에서 만든 컨트롤이 포함된 대화 상자의 창 프로시저에서 기본 글꼴을 사용하고 텍스트를 사용자 지정 색으로 표시하여 WM_DRAWITEM 메시지를 처리합니다. WM_DRAWITEM을 처리할 때 BeginPaintEndPaint를 호출할 필요가 없습니다.

case WM_DRAWITEM:
{
    LPDRAWITEMSTRUCT pDIS = (LPDRAWITEMSTRUCT)lParam;
    if (pDIS->hwndItem == g_myStatic)
    {
        SetTextColor(pDIS->hDC, RGB(100, 0, 100));
        WCHAR staticText[99];
        int len = SendMessage(myStatic, WM_GETTEXT, 
            ARRAYSIZE(staticText), (LPARAM)staticText);
        TextOut(pDIS->hDC, pDIS->rcItem.left, pDIS->rcItem.top, staticText, len);
    }
    return TRUE;
}

소유자가 그린 컨트롤에 대한 자세한 내용은 소유자가 그린 목록 상자 만들기소유자가 그린 콤보 상자를 참조하세요.

기존 컨트롤의 창 클래스 서브클래싱

기존 컨트롤을 서브클래싱하는 것은 사용자 지정 컨트롤을 만드는 또 다른 방법입니다. 서브클래스 프로시저는 선택한 동작에 영향을 주는 메시지를 처리하여 컨트롤의 선택한 동작을 변경할 수 있습니다. 다른 모든 메시지는 컨트롤의 원래 창 프로시저로 전달됩니다. 예를 들어 애플리케이션은 컨트롤을 서브클래싱하고 WM_PAINT 메시지를 처리하여 읽기 전용 단일 줄 편집 컨트롤에서 텍스트 옆에 작은 비트맵을 표시할 수 있습니다. 자세한 내용은 창 프로시저 정보컨트롤 서브클래싱을 참조하세요.

애플리케이션 정의 창 클래스 구현

명시적으로 기존 컨트롤을 기준으로 하지 않는 컨트롤을 만들려면 애플리케이션에서 창 클래스를 만들고 등록해야 합니다. 사용자 지정 컨트롤에 대한 애플리케이션 정의 창 클래스를 등록하는 프로세스는 일반 창에 대한 클래스를 등록하는 프로세스와 동일합니다. 사용자 지정 컨트롤을 만들려면 CreateWindowEx 함수 또는 대화 상자 템플릿에서 창 클래스의 이름을 지정합니다. 각 클래스에는 고유한 이름, 해당 창 프로시저 및 기타 정보가 있어야 합니다.

최소한 창 프로시저는 컨트롤을 그립니다. 애플리케이션에서 컨트롤을 사용하여 사용자가 정보를 입력하도록 하는 경우 창 프로시저는 키보드와 마우스의 입력 메시지도 처리하고 부모 창에 알림 메시지를 보냅니다. 또한 컨트롤이 제어 메시지를 지원하는 경우 창 프로시저는 부모 창 또는 다른 창에서 보낸 메시지를 처리합니다. 예를 들어 컨트롤은 대화 상자에서 보낸 WM_GETDLGCODE 메시지를 처리하여 지정된 방식으로 키보드 입력을 처리하도록 대화 상자에 지시하는 경우가 많습니다.

애플리케이션 정의 컨트롤에 대한 창 프로시저는 메시지가 컨트롤 작업에 영향을 주는 경우 다음 표의 미리 정의된 컨트롤 메시지를 처리해야 합니다.

메시지 권장
WM_GETDLGCODE 컨트롤이 Enter, Esc, Tab 또는 화살표 키를 사용하는 경우 처리합니다. IsDialogMessage 함수는 이 메시지를 대화 상자의 컨트롤로 보내 키를 처리할지 아니면 컨트롤에 전달할지를 결정합니다.
WM_GETFONT WM_SETFONT 메시지도 처리되면 처리합니다.
WM_GETTEXT 컨트롤 텍스트가 CreateWindowEx 함수에서 지정한 제목과 같지 않은 경우 처리합니다.
WM_GETTEXTLENGTH 컨트롤 텍스트가 CreateWindowEx 함수에서 지정한 제목과 같지 않은 경우 처리합니다.
WM_KILLFOCUS 컨트롤에 캐럿, 포커스 사각형 또는 다른 항목이 표시되어 입력 포커스가 있음을 나타내는 경우 처리합니다.
WM_SETFOCUS 컨트롤에 캐럿, 포커스 사각형 또는 다른 항목이 표시되어 입력 포커스가 있음을 나타내는 경우 처리합니다.
WM_SETTEXT 컨트롤 텍스트가 CreateWindowEx 함수에서 지정한 제목과 같지 않은 경우 처리합니다.
WM_SETFONT 컨트롤에 텍스트가 표시되는 경우 처리합니다. 시스템은 DS_SETFONT 스타일이 있는 대화 상자를 만들 때 이 메시지를 보냅니다.

 

애플리케이션 정의 컨트롤 메시지는 지정된 컨트롤과 관련이 있으며 SendMessage 또는 SendDlgItemMessage 함수를 사용하여 컨트롤로 명시적으로 전송되어야 합니다. 각 메시지의 숫자 값은 고유해야 하며 다른 창 메시지의 값과 충돌해서는 안 됩니다. 애플리케이션 정의 메시지 값이 충돌하지 않도록 하려면 애플리케이션이 WM_USER 값에 고유한 숫자를 추가하여 각 값을 만들어야 합니다.

컨트롤에서 알림 보내기

호스트 애플리케이션이 이러한 이벤트에 응답할 수 있도록 부모 창에 이벤트 알림을 보내려면 사용자 지정 컨트롤이 필요할 수 있습니다. 예를 들어 사용자 지정 목록 보기는 사용자가 항목을 선택할 때 알림을 보내고, 항목을 두 번 클릭할 때 다른 알림을 보낼 수 있습니다.

알림은 WM_COMMAND 또는 WM_NOTIFY 메시지로 전송됩니다. WM_NOTIFY 메시지는 WM_COMMAND 메시지보다 더 많은 정보를 전달합니다.

컨트롤 식별자는 애플리케이션이 메시지를 보내는 컨트롤을 식별하는 데 사용하는 고유 번호입니다. 애플리케이션은 컨트롤을 만들 때 컨트롤의 식별자를 설정합니다. 애플리케이션은 CreateWindowEx 함수의 hMenu 매개 변수 또는 DLGITEMTEMPLATEEX 구조체의 id 멤버에서 식별자를 지정합니다.

컨트롤 자체가 컨트롤 식별자를 설정하지 않으므로 컨트롤은 알림 메시지를 보내기 전에 식별자를 검색해야 합니다. 컨트롤은 GetDlgCtrlID 함수를 사용하여 자체 컨트롤 식별자를 검색해야 합니다. 컨트롤 식별자는 컨트롤을 만들 때 메뉴 핸들로 지정되지만 GetMenu 함수를 사용하여 식별자를 검색할 수 없습니다. 또는 컨트롤은 WM_CREATE 메시지를 처리하는 동안 CREATESTRUCT 구조체의 hMenu 멤버에서 식별자를 검색할 수 있습니다.

다음 예제에서는 hwndControl이 컨트롤 창의 핸들이고 CN_VALUECHANGED가 사용자 지정 알림 정의인 경우 컨트롤별 알림을 보내는 두 가지 방법을 보여 줍니다.

 // Send as WM_COMMAND.
SendMessage(GetParent(hwndControl), 
    WM_COMMAND,
    MAKEWPARAM(GetDlgCtrlID(hwndControl), CN_VALUECHANGED),
    (LPARAM)hwndControl);

// Send as WM_NOTIFY.           
NMHDR nmh;
nmh.code = CN_VALUECHANGED;
nmh.idFrom = GetDlgCtrlID(hwndControl);
nmh.hwndFrom = hwndControl;
SendMessage(GetParent(hwndControl), 
    WM_NOTIFY, 
    (WPARAM)hwndControl, 
    (LPARAM)&nmh);

NMHDR 구조체는 추가 정보를 포함하는 더 큰 컨트롤 정의 구조체의 일부일 수 있습니다. 이 예제에서는 컨트롤의 이전 값과 새 값이 이 구조체에 포함될 수 있습니다. (이러한 확장 구조는 많은 표준 알림과 함께 사용됩니다. 예를 들어 NMLISTVIEW 구조체를 사용하는 LVN_INSERTITEM을 참조하세요.)

액세스 가능성

모든 공통 컨트롤은 화면 읽기 프로그램과 같은 접근성 기술 애플리케이션에서 프로그래밍 방식으로 액세스할 수 있도록 하는 MSAA(Microsoft Active Accessibility)를 지원합니다. 또한 MSAA를 사용하면 최신 기술인 UI 자동화가 컨트롤과 상호 작용할 수 있습니다.

사용자 지정 컨트롤은 IAccessible 인터페이스(MSAA 지원)나 UI 자동화 인터페이스를 구현하거나 둘 다를 구현해야 합니다. 그렇지 않으면 접근성 기술 제품은 컨트롤 창에 대한 매우 제한된 정보만 얻을 수 있고 컨트롤의 속성에 액세스할 수 없으며 컨트롤에서 이벤트를 트리거할 수 없습니다.

컨트롤에 액세스할 수 있도록 하는 방법에 대한 자세한 내용은 Windows Automation API를 참조하세요.

개념

일반 컨트롤 참조

사용자 지정 그리기를 사용하여 컨트롤의 모양 사용자 지정

컨트롤 메시지

소유자가 그린 컨트롤과 함께 시각적 스타일 사용