다음을 통해 공유


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

이 항목에서는 시각적 스타일 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. 텍스트를 렌더링하려면 GetThemeBackgroundContentRect에 의해 반환된 사각형의 좌표를 기반으로 DrawThemeText 또는 DrawThemeTextEx를 사용합니다. 이러한 함수는 지정된 컨트롤 파트 및 상태에 대한 테마의 글꼴 또는 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");

시각적 개체 스타일 사용

시각적 스타일