다음을 통해 공유


사용자 지정 및 Owner-Drawn 컨트롤과 함께 비주얼 스타일 사용

이 항목에서는 비주얼 스타일 API를 사용하여 사용자 지정 컨트롤 또는 소유자가 그린 컨트롤에 비주얼 스타일을 적용하는 방법을 설명합니다.

비주얼 스타일을 사용하여 컨트롤 그리기

비주얼 스타일은 ComCtrl32.dll 버전 6 이상에서 지원됩니다. 애플리케이션이 ComCtrl32.dll 버전 6 이상을 사용하도록 구성되어 있고 해당 버전을 시스템에서 사용할 수 있는 경우 현재 비주얼 스타일이 애플리케이션의 모든 공통 컨트롤에 자동으로 적용됩니다. 그러나 현재 비주얼 스타일은 사용자 지정 컨트롤 또는 소유자가 그린 컨트롤에 자동으로 적용되지 않습니다. 애플리케이션에는 비주얼 스타일을 사용할 수 있는지 여부를 확인하는 코드가 포함되어야 하며, 이 경우 비주얼 스타일 API를 사용하여 현재 선택한 비주얼 스타일을 사용자 지정 및 소유자가 그린 컨트롤에 적용해야 합니다.

비주얼 스타일을 사용할 수 있는지 확인하려면 IsAppThemed 함수를 호출합니다. 비주얼 스타일을 사용할 수 없는 경우 대체 코드를 사용하여 컨트롤을 그립니다.

비주얼 스타일을 사용할 수 있는 경우 DrawThemeText 같은 비주얼 스타일 함수를 사용하여 컨트롤을 렌더링할 수 있습니다. DrawThemeTextEx 사용하면 텍스트 모양을 사용자 지정하고 테마 글꼴의 일부 속성을 유지하면서 다른 속성을 수정할 수 있습니다.

현재 비주얼 스타일에서 컨트롤을 그리려면

  1. OpenThemeData호출하여 비주얼 스타일을 적용할 컨트롤의 hwnd 컨트롤의 형식을 설명하는 클래스 목록을 전달합니다. 클래스는 Vssym32.h에 정의됩니다. OpenThemeData HTHEME 핸들을 반환하지만 비주얼 스타일 관리자가 비활성화되어 있거나 현재 비주얼 스타일이 지정된 컨트롤에 대한 특정 정보를 제공하지 않으면 함수는 NULL 반환합니다. 반환 값이 NULL 경우 비주얼 스타일이 아닌 그리기 함수를 사용합니다.
  2. 컨트롤 배경을 그리려면 DrawThemeBackground또는 DrawThemeBackgroundEx호출합니다.
  3. 콘텐츠 사각형의 위치를 확인하려면 GetThemeBackgroundContentRect호출합니다.
  4. 텍스트를 렌더링하려면 DrawThemeText 또는 DrawThemeTextEx를 사용하여 GetThemeBackgroundContentRect에서 반환된 사각형을 기준으로 좌표를 설정합니다. 이러한 함수는 테마의 글꼴에서 지정된 컨트롤 부분 및 상태에 대한 텍스트를 렌더링하거나 현재 디바이스 컨텍스트(DC)로 선택된 글꼴에서 텍스트를 렌더링할 수 있습니다.
  5. 컨트롤이 WM_DESTROY 메시지를 받으면 CloseThemeData 호출하여 OpenThemeData호출할 때 반환된 테마 핸들을 해제합니다.

다음 예제 코드는 현재 비주얼 스타일에서 단추 컨트롤을 그리는 한 가지 방법을 보여 줍니다.

HTHEME hTheme = NULL;

hTheme = OpenThemeData(hwndButton, L"Button");
// ...
DrawMyControl(hDC, hwndButton, hTheme, iState);
// ...
if (hTheme)
{
    CloseThemeData(hTheme);
}


void DrawMyControl(HDC hDC, HWND hwndButton, HTHEME hTheme, int iState)
{
    RECT rc, rcContent;
    TCHAR szButtonText[255];
    HRESULT hr;
    size_t cch;

    GetWindowRect(hwndButton, &rc);
    GetWindowText(hwndButton, szButtonText,
                  (sizeof(szButtonText) / sizeof(szButtonText[0])+1));
    hr = StringCchLength(szButtonText,
         (sizeof(szButtonText) / sizeof(szButtonText[0])), &cch);
    if (hTheme)
    {
        hr = DrawThemeBackground(hTheme, hDC, BP_PUSHBUTTON, iState, &rc, 0);
        if (SUCCEEDED(hr))
        {
            hr = GetThemeBackgroundContentRect(hTheme, hDC, BP_PUSHBUTTON, 
                    iState, &rc, &rcContent);
        }

        if (SUCCEEDED(hr))
        {
            hr = DrawThemeText(hTheme, hDC, BP_PUSHBUTTON, iState, 
                    szButtonText, cch,
                    DT_CENTER | DT_VCENTER | DT_SINGLELINE,
                    0, &rcContent);
        }

    }
    else
    {
        // Draw the control without using visual styles.
    }
}

다음 예제 코드는 서브클래스 단추 컨트롤에 대한 WM_PAINT 메시지 처리기에 있습니다. 컨트롤의 텍스트는 비주얼 스타일 글꼴로 그려지지만 색은 컨트롤의 상태에 따라 애플리케이션에서 정의됩니다.

// textColor is a COLORREF whose value has been set according to whether the button is "hot".
// paint is the PAINTSTRUCT whose members are filled in by BeginPaint.
HTHEME theme = OpenThemeData(hWnd, L"button");
if (theme)
{
    DTTOPTS opts = { 0 };
    opts.dwSize = sizeof(opts);
    opts.crText = textColor;
    opts.dwFlags |= DTT_TEXTCOLOR;
    WCHAR caption[255];
    size_t cch;
    GetWindowText(hWnd, caption, 255);
    StringCchLength(caption, 255, &cch);
    DrawThemeTextEx(theme, paint.hdc, BP_PUSHBUTTON, CBS_UNCHECKEDNORMAL, 
        caption, cch, DT_CENTER | DT_VCENTER | DT_SINGLELINE, 
        &paint.rcPaint, &opts);
    CloseThemeData(theme);
}
else
{
    // Draw the control without using visual styles.
}

다른 컨트롤의 파트를 사용하고 각 파트를 별도로 렌더링할 수 있습니다. 예를 들어, 눈금이 있는 달력 컨트롤의 경우 테마 핸들을 다음과 같이 가져와서 형성된 그리드의 각 사각형을 도구 모음 단추로 처리할 수 있습니다.

OpenThemeData(hwnd, L"Toolbar");

지정된 컨트롤에 대해 OpenThemeData 여러 번 호출하고 적절한 테마 핸들을 사용하여 다른 부분을 그려 컨트롤 파트를 혼합하고 일치시킬 수 있습니다. 그러나 일부 비주얼 스타일에서는 특정 부분이 다른 부분과 호환되지 않을 수 있습니다.

활성 비주얼 스타일에서 컨트롤을 렌더링하는 또 다른 방법은 시스템 색을 사용하는 것입니다. 예를 들어 시스템 색을 사용하여 DrawThemeTextEx 함수를 호출할 때 텍스트 색을 설정할 수 있습니다. 대부분의 시스템 색은 비주얼 스타일 파일을 적용할 때 설정됩니다.

테마 변경 내용에 응답

컨트롤이 WM_THEMECHANGED 메시지를 수신하고 테마에 대한 전역 핸들을 보유하고 있는 경우, 다음 작업을 수행해야 합니다.

  • CloseThemeData 호출하여 기존 테마 핸들을 닫습니다.
  • OpenThemeData 호출하여 새로 로드된 비주얼 스타일에 대한 테마 핸들을 가져옵니다.

다음 예제에서는 두 호출을 보여 줍니다.

case WM_THEMECHANGED:
     CloseThemeData (g_hTheme);
     g_hTheme = OpenThemeData (hwnd, L"MyClassName");

비주얼 스타일 사용하도록 설정

비주얼 스타일