텍스트 스크롤 방법

이 섹션에서는 사용자가 텍스트를 스크롤할 수 있도록 애플리케이션의 주 창 프로시저에서 변경할 수 있는 사항에 대해 설명합니다. 이 섹션의 예에서는 텍스트 문자열 배열을 만들기 및 표시하고 WM_HSCROLLWM_VSCROLL 스크롤 막대 메시지를 처리하여 사용자가 텍스트를 수직 및 수평으로 스크롤할 수 있습니다.

알아야 하는 작업

기술

필수 구성 요소

  • C/C++
  • Windows 사용자 인터페이스 프로그래밍

지침

WM_CREATE 메시지 처리

스크롤 단위는 일반적으로 WM_CREATE 메시지를 처리하는 동안 설정됩니다. 창의 DC(디바이스 컨텍스트)와 연결된 글꼴 크기에 따라 스크롤 단위를 지정하는 것이 편리합니다. 특정 DC의 글꼴 크기를 검색하려면 GetTextMetrics 함수를 사용합니다.

이 섹션의 예에서 하나의 세로 스크롤 단위는 문자 셀의 높이에 외부 행간을 더한 것과 같습니다. 하나의 가로 스크롤 단위는 문자 셀의 평균 너비와 같습니다. 따라서 가로 스크롤 위치는 화면 글꼴이 고정 너비가 아닌 한 실제 문자와 일치하지 않습니다.

WM_SIZE 메시지 처리

WM_SIZE 메시지를 처리할 때 클라이언트 영역의 크기와 표시할 텍스트 줄 수를 반영하여 스크롤 범위와 스크롤 위치를 조정하면 편리합니다.

SetScrollInfo 함수는 최소 및 최대 위치 값, 페이지 크기 및 스크롤 막대의 스크롤 위치를 설정합니다.

WM_HSCROLL 및 WM_VSCROLL 메시지 처리

스크롤 막대는 사용자가 스크롤 막대를 클릭하거나 스크롤 상자를 끌 때마다 창 프로시저에 WM_HSCROLLWM_VSCROLL 메시지를 보냅니다. WM_VSCROLLWM_HSCROLL의 하위 단어에는 각각 스크롤 작업의 방향과 크기를 나타내는 요청 코드가 포함되어 있습니다.

WM_HSCROLLWM_VSCROLL 메시지가 처리될 때 스크롤 막대 요청 코드가 검사되고 스크롤 증분이 계산됩니다. 현재 스크롤 위치에 증분을 적용한 후 창은 ScrollWindowEx 함수를 사용하여 새 위치로 스크롤되고 스크롤 상자의 위치는 SetScrollInfo 함수를 사용하여 조정됩니다.

창을 스크롤한 후 해당 클라이언트 영역의 파트가 무효화됩니다. 유효하지 않은 영역이 업데이트되었는지 확인하기 위해 UpdateWindow 함수를 사용하여 WM_PAINT 메시지를 생성합니다.

WM_PAINT 메시지 처리

WM_PAINT 메시지를 처리할 때 창의 유효하지 않은 부분에 표시하려는 텍스트 줄을 그리는 것이 편리합니다. 다음 예에서는 현재 스크롤 위치와 유효하지 않은 영역의 크기를 사용하여 유효하지 않은 영역 내의 줄 범위를 결정하여 표시합니다.

스크롤 텍스트 예

다음 예에서는 클라이언트 영역에 텍스트를 표시하는 창에 대한 창 프로시저입니다. 이 예는 수평 및 수직 스크롤 막대의 입력에 대한 응답으로 텍스트를 스크롤하는 방법을 보여 줍니다.

#include "strsafe.h"

LRESULT CALLBACK MyTextWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc; 
PAINTSTRUCT ps; 
TEXTMETRIC tm; 
SCROLLINFO si; 
 
// These variables are required to display text. 
static int xClient;     // width of client area 
static int yClient;     // height of client area 
static int xClientMax;  // maximum width of client area 
 
static int xChar;       // horizontal scrolling unit 
static int yChar;       // vertical scrolling unit 
static int xUpper;      // average width of uppercase letters 
 
static int xPos;        // current horizontal scrolling position 
static int yPos;        // current vertical scrolling position 
 
int i;                  // loop counter 
int x, y;               // horizontal and vertical coordinates
 
int FirstLine;          // first line in the invalidated area 
int LastLine;           // last line in the invalidated area 
HRESULT hr;
size_t abcLength;        // length of an abc[] item 

// Create an array of lines to display. 
#define LINES 28 
static TCHAR *abc[] = { 
       TEXT("anteater"),  TEXT("bear"),      TEXT("cougar"), 
       TEXT("dingo"),     TEXT("elephant"),  TEXT("falcon"), 
       TEXT("gazelle"),   TEXT("hyena"),     TEXT("iguana"), 
       TEXT("jackal"),    TEXT("kangaroo"),  TEXT("llama"), 
       TEXT("moose"),     TEXT("newt"),      TEXT("octopus"), 
       TEXT("penguin"),   TEXT("quail"),     TEXT("rat"), 
       TEXT("squid"),     TEXT("tortoise"),  TEXT("urus"), 
       TEXT("vole"),      TEXT("walrus"),    TEXT("xylophone"), 
       TEXT("yak"),       TEXT("zebra"),
       TEXT("This line contains words, but no character. Go figure."),
       TEXT("")
     }; 
 
switch (uMsg) 
{ 
    case WM_CREATE : 
        // Get the handle to the client area's device context. 
        hdc = GetDC (hwnd); 
 
        // Extract font dimensions from the text metrics. 
        GetTextMetrics (hdc, &tm); 
        xChar = tm.tmAveCharWidth; 
        xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * xChar/2; 
        yChar = tm.tmHeight + tm.tmExternalLeading; 
 
        // Free the device context. 
        ReleaseDC (hwnd, hdc); 
 
        // Set an arbitrary maximum width for client area. 
        // (xClientMax is the sum of the widths of 48 average 
        // lowercase letters and 12 uppercase letters.) 
        xClientMax = 48 * xChar + 12 * xUpper; 
 
        return 0; 
 
    case WM_SIZE: 
 
        // Retrieve the dimensions of the client area. 
        yClient = HIWORD (lParam); 
        xClient = LOWORD (lParam); 
 
        // Set the vertical scrolling range and page size
        si.cbSize = sizeof(si); 
        si.fMask  = SIF_RANGE | SIF_PAGE; 
        si.nMin   = 0; 
        si.nMax   = LINES - 1; 
        si.nPage  = yClient / yChar; 
        SetScrollInfo(hwnd, SB_VERT, &si, TRUE); 
 
        // Set the horizontal scrolling range and page size. 
        si.cbSize = sizeof(si); 
        si.fMask  = SIF_RANGE | SIF_PAGE; 
        si.nMin   = 0; 
        si.nMax   = 2 + xClientMax / xChar; 
        si.nPage  = xClient / xChar; 
        SetScrollInfo(hwnd, SB_HORZ, &si, TRUE); 
 
        return 0; 
    case WM_HSCROLL:
        // Get all the vertial scroll bar information.
        si.cbSize = sizeof (si);
        si.fMask  = SIF_ALL;

        // Save the position for comparison later on.
        GetScrollInfo (hwnd, SB_HORZ, &si);
        xPos = si.nPos;
        switch (LOWORD (wParam))
        {
        // User clicked the left arrow.
        case SB_LINELEFT: 
            si.nPos -= 1;
            break;
              
        // User clicked the right arrow.
        case SB_LINERIGHT: 
            si.nPos += 1;
            break;
              
        // User clicked the scroll bar shaft left of the scroll box.
        case SB_PAGELEFT:
            si.nPos -= si.nPage;
            break;
              
        // User clicked the scroll bar shaft right of the scroll box.
        case SB_PAGERIGHT:
            si.nPos += si.nPage;
            break;
              
        // User dragged the scroll box.
        case SB_THUMBTRACK: 
            si.nPos = si.nTrackPos;
            break;
              
        default :
            break;
        }

        // Set the position and then retrieve it.  Due to adjustments
        // by Windows it may not be the same as the value set.
        si.fMask = SIF_POS;
        SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
        GetScrollInfo (hwnd, SB_HORZ, &si);
         
        // If the position has changed, scroll the window.
        if (si.nPos != xPos)
        {
            ScrollWindow(hwnd, xChar * (xPos - si.nPos), 0, NULL, NULL);
        }

        return 0;
         
    case WM_VSCROLL:
        // Get all the vertial scroll bar information.
        si.cbSize = sizeof (si);
        si.fMask  = SIF_ALL;
        GetScrollInfo (hwnd, SB_VERT, &si);

        // Save the position for comparison later on.
        yPos = si.nPos;
        switch (LOWORD (wParam))
        {

        // User clicked the HOME keyboard key.
        case SB_TOP:
            si.nPos = si.nMin;
            break;
              
        // User clicked the END keyboard key.
        case SB_BOTTOM:
            si.nPos = si.nMax;
            break;
              
        // User clicked the top arrow.
        case SB_LINEUP:
            si.nPos -= 1;
            break;
              
        // User clicked the bottom arrow.
        case SB_LINEDOWN:
            si.nPos += 1;
            break;
              
        // User clicked the scroll bar shaft above the scroll box.
        case SB_PAGEUP:
            si.nPos -= si.nPage;
            break;
              
        // User clicked the scroll bar shaft below the scroll box.
        case SB_PAGEDOWN:
            si.nPos += si.nPage;
            break;
              
        // User dragged the scroll box.
        case SB_THUMBTRACK:
            si.nPos = si.nTrackPos;
            break;
              
        default:
            break; 
        }

        // Set the position and then retrieve it.  Due to adjustments
        // by Windows it may not be the same as the value set.
        si.fMask = SIF_POS;
        SetScrollInfo (hwnd, SB_VERT, &si, TRUE);
        GetScrollInfo (hwnd, SB_VERT, &si);

        // If the position has changed, scroll window and update it.
        if (si.nPos != yPos)
        {                    
            ScrollWindow(hwnd, 0, yChar * (yPos - si.nPos), NULL, NULL);
            UpdateWindow (hwnd);
        }

        return 0;
         
    case WM_PAINT :
        // Prepare the window for painting.
        hdc = BeginPaint (hwnd, &ps);

        // Get vertical scroll bar position.
        si.cbSize = sizeof (si);
        si.fMask  = SIF_POS;
        GetScrollInfo (hwnd, SB_VERT, &si);
        yPos = si.nPos;

        // Get horizontal scroll bar position.
        GetScrollInfo (hwnd, SB_HORZ, &si);
        xPos = si.nPos;

        // Find painting limits.
        FirstLine = max (0, yPos + ps.rcPaint.top / yChar);
        LastLine = min (LINES - 1, yPos + ps.rcPaint.bottom / yChar);
         
        for (i = FirstLine; i <= LastLine; i++)
        {
            x = xChar * (1 - xPos);
            y = yChar * (i - yPos);
              
            // Note that "55" in the following depends on the 
            // maximum size of an abc[] item. Also, you must include
            // strsafe.h to use the StringCchLength function.
            hr = StringCchLength(abc[i], 55, &abcLength);
            if ((FAILED(hr))|(abcLength == NULL))
            {
                //
                // TODO: write error handler
                //
            }

            // Write a line of text to the client area.
            TextOut(hdc, x, y, abc[i], abcLength); 
        }

        // Indicate that painting is finished.
        EndPaint (hwnd, &ps);
        return 0;
         
    case WM_DESTROY :
        PostQuitMessage (0);
        return 0;
    }

    return DefWindowProc (hwnd, uMsg, wParam, lParam);
}

스크롤 막대 사용

Windows 공용 컨트롤 데모(CppWindowsCommonControls)