브러시 사용

브러시를 사용하여 GDI(그래픽 디바이스 인터페이스) 함수를 사용하여 거의 모든 셰이프의 내부를 그릴 수 있습니다. 여기에는 사각형, 타원, 다각형 및 경로의 내부가 포함됩니다. 애플리케이션의 요구 사항에 따라 지정된 색의 단색 브러시, 스톡 브러시, 해치 브러시 또는 패턴 브러시를 사용할 수 있습니다.

이 섹션에는 사용자 지정 브러시 대화 상자의 생성을 보여 주는 코드 샘플이 포함되어 있습니다. 대화 상자에는 시스템에서 브러시로 사용하는 비트맵을 나타내는 표가 포함되어 있습니다. 사용자는 이 그리드를 사용하여 패턴 브러시 비트맵을 만든 다음, 패턴 테스트 단추를 클릭하여 사용자 지정 패턴을 볼 수 있습니다.

다음 그림에서는 사용자 지정 브러시 대화 상자를 사용하여 만든 패턴을 보여 줍니다.

사용자 지정 브러시 대화 상자의 스크린샷

대화 상자를 표시하려면 먼저 대화 상자 템플릿을 만들어야 합니다. 다음 대화 상자 템플릿은 사용자 지정 브러시 대화 상자를 정의합니다.

CustBrush DIALOG 6, 18, 160, 118 
STYLE WS_DLGFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION 
CAPTION "Custom Brush" 
FONT 8, "MS Sans Serif" 
BEGIN 
    CONTROL         "", IDD_GRID, "Static", SS_BLACKFRAME | 
                    WS_CHILD, 3, 2, 83, 79 
    CONTROL         "", IDD_RECT, "Static", SS_BLACKFRAME | 
                    WS_CHILD, 96, 11, 57, 28 
    PUSHBUTTON      "Test Pattern", IDD_PAINTRECT, 96, 47, 57, 14 
    PUSHBUTTON      "OK", IDD_OK, 29, 98, 40, 14 
    PUSHBUTTON      "Cancel", IDD_CANCEL, 92, 98, 40, 14 
END 

사용자 지정 브러시 대화 상자에는 비트맵 그리드 창, 패턴 보기 창 및 테스트 패턴, 확인취소라는 레이블이 지정된 3개의 푸시 단추의 5가지 컨트롤이 포함되어 있습니다. 테스트 패턴 푸시 단추를 사용하면 사용자가 패턴을 볼 수 있습니다. 대화 상자 템플릿은 대화 상자 창의 전체 차원을 지정하고, 각 컨트롤에 값을 할당하고, 각 컨트롤의 위치를 지정합니다. 자세한 내용은 대화 상자를 참조하세요.

대화 상자 템플릿의 컨트롤 값은 애플리케이션의 헤더 파일에서 다음과 같이 정의된 상수입니다.

#define IDD_GRID      120 
#define IDD_RECT      121 
#define IDD_PAINTRECT 122 
#define IDD_OK        123 
#define IDD_CANCEL    124 

대화 상자 템플릿을 만들고 애플리케이션의 리소스 정의 파일에 포함하면 대화 상자를 작성해야 합니다. 이 절차에서는 시스템에서 대화 상자로 보내는 메시지를 처리합니다. 애플리케이션의 소스 코드에서 발췌한 다음에서는 사용자 지정 브러시 대화 상자의 대화 상자 프로시저와 호출하는 두 개의 애플리케이션 정의 함수를 보여 줍니다.

BOOL CALLBACK BrushDlgProc( HWND hdlg, UINT message, LONG wParam, 
                            LONG lParam) 
{ 
    static HWND hwndGrid;       // grid-window control  
    static HWND hwndBrush;      // pattern-brush control  
    static RECT rctGrid;        // grid-window rectangle  
    static RECT rctBrush;       // pattern-brush rectangle  
    static UINT bBrushBits[8];  // bitmap bits  
    static RECT rect[64];       // grid-cell array  
    static HBITMAP hbm;         // bitmap handle  
    HBRUSH hbrush;              // current brush  
    HBRUSH hbrushOld;           // default brush  
    HRGN hrgnCell;              // test-region handle  
    HDC hdc;                    // device context (DC) handle  
    int x, y, deltaX, deltaY;   // drawing coordinates  
    POINTS ptlHit;              // mouse coordinates  
    int i;                      // count variable  
 
    switch (message) 
        { 
        case WM_INITDIALOG: 
 
            // Retrieve a window handle for the grid-window and  
            // pattern-brush controls.  
 
            hwndGrid = GetDlgItem(hdlg, IDD_GRID); 
            hwndBrush = GetDlgItem(hdlg, IDD_RECT); 
 
            // Initialize the array of bits that defines the  
            // custom brush pattern with the value 1 to produce a  
            // solid white brush.  

            for (i=0; i<8; i++) 
                bBrushBits[i] = 0xFF; 
 
            // Retrieve dimensions for the grid-window and pattern- 
            // brush controls.  
 
            GetClientRect(hwndGrid, &rctGrid); 
            GetClientRect(hwndBrush, &rctBrush); 
 
            // Determine the width and height of a single cell.  
 
            deltaX = (rctGrid.right - rctGrid.left)/8; 
            deltaY = (rctGrid.bottom - rctGrid.top)/8; 
 
            // Initialize the array of cell rectangles.  
 
            for (y=rctGrid.top, i=0; y < rctGrid.bottom; y += deltaY)
            { 
                for(x=rctGrid.left; x < (rctGrid.right - 8) && i < 64; 
                        x += deltaX, i++) 
                { 
                    rect[i].left = x; rect[i].top = y; 
                    rect[i].right = x + deltaX; 
                    rect[i].bottom = y + deltaY; 
                } 
            } 
            return FALSE; 
 
 
        case WM_PAINT: 

            // Draw the grid.  
 
            hdc = GetDC(hwndGrid); 
 
            for (i=rctGrid.left; i<rctGrid.right; 
                 i+=(rctGrid.right - rctGrid.left)/8)
            { 
                 MoveToEx(hdc, i, rctGrid.top, NULL); 
                 LineTo(hdc, i, rctGrid.bottom); 
            } 
            for (i=rctGrid.top; i<rctGrid.bottom; 
                 i+=(rctGrid.bottom - rctGrid.top)/8)
            { 
                 MoveToEx(hdc, rctGrid.left, i, NULL); 
                 LineTo(hdc, rctGrid.right, i); 
            } 
            ReleaseDC(hwndGrid, hdc); 
            return FALSE; 
 
 
        case WM_LBUTTONDOWN: 
 
            // Store the mouse coordinates in a POINT structure.  
 
            ptlHit = MAKEPOINTS((POINTS FAR *)lParam); 
 
            // Create a rectangular region with dimensions and  
            // coordinates that correspond to those of the grid  
            // window.  
 
            hrgnCell = CreateRectRgn(rctGrid.left, rctGrid.top, 
                        rctGrid.right, rctGrid.bottom); 
 
            // Retrieve a window DC for the grid window.  
 
            hdc = GetDC(hwndGrid); 
 
            // Select the region into the DC.  
 
            SelectObject(hdc, hrgnCell); 
 
            // Test for a button click in the grid-window rectangle.  
 
            if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y))
            { 
                // A button click occurred in the grid-window  
                // rectangle; isolate the cell in which it occurred.  
 
                for(i=0; i<64; i++)
                { 
                    DeleteObject(hrgnCell); 
 
                    hrgnCell = CreateRectRgn(rect[i].left,  
                               rect[i].top, 
                               rect[i].right, rect[i].bottom); 
 
                    if (PtInRegion(hrgnCell, ptlHit.x, ptlHit.y))
                    { 
                        InvertRgn(hdc, hrgnCell); 
 
                        // Set the appropriate brush bits.  
 
                         if (i % 8 == 0) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x80; 
                         else if (i % 8 == 1) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x40; 
                         else if (i % 8 == 2) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x20; 
                         else if (i % 8 == 3) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x10; 
                         else if (i % 8 == 4) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x08; 
                         else if (i % 8 == 5) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x04; 
                         else if (i % 8 == 6) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x02; 
                         else if (i % 8 == 7) 
                            bBrushBits[i/8] = bBrushBits[i/8] ^ 0x01; 
 
                      // Exit the "for" loop after the bit is set.  
 
                         break; 
                    } // end if  
 
                } // end for  
 
            } // end if  
 
            // Release the DC for the control.  
 
            ReleaseDC(hwndGrid, hdc); 
            return TRUE; 
 
 
        case WM_COMMAND: 
            switch (wParam)
            { 
               case IDD_PAINTRECT: 
 
                    hdc = GetDC(hwndBrush); 
 
                    // Create a monochrome bitmap.  
 
                    hbm = CreateBitmap(8, 8, 1, 1, 
                          (LPBYTE)bBrushBits); 
 
                    // Select the custom brush into the DC.  
 
                    hbrush = CreatePatternBrush(hbm); 
 
                    hbrushOld = SelectObject(hdc, hbrush); 
 
                    // Use the custom brush to fill the rectangle.  
 
                    Rectangle(hdc, rctBrush.left, rctBrush.top, 
                              rctBrush.right, rctBrush.bottom); 
 
                    // Clean up memory.  
                    SelectObject(hdc, hbrushOld); 
                    DeleteObject(hbrush); 
                    DeleteObject(hbm); 
 
                    ReleaseDC(hwndBrush, hdc); 
                    return TRUE; 
 
                case IDD_OK: 
 
                case IDD_CANCEL: 
                    EndDialog(hdlg, TRUE); 
                    return TRUE; 
 
            } // end switch  
            break; 
        default: 
            return FALSE; 
        } 
} 
 
 
int GetStrLngth(LPTSTR cArray) 
{ 
    int i = 0; 
 
    while (cArray[i++] != 0); 
    return i-1; 
 
} 
 
DWORD RetrieveWidth(LPTSTR cArray, int iLength) 
{ 
    int i, iTmp; 
    double dVal, dCount; 
 
    dVal = 0.0; 
    dCount = (double)(iLength-1); 
    for (i=0; i<iLength; i++)
    { 
        iTmp = cArray[i] - 0x30; 
        dVal = dVal + (((double)iTmp) * pow(10.0, dCount--)); 
    } 
 
    return (DWORD)dVal; 
} 

사용자 지정 브러시 대화 상자의 대화 상자 프로시저는 다음 표에 설명된 대로 4개의 메시지를 처리합니다.

메시지 작업
WM_INITDIALOG 그리드 창 및 패턴 브러시 컨트롤에 대한 창 핸들 및 차원을 검색하고, 그리드 창 컨트롤에서 단일 셀의 크기를 계산하고, 그리드 셀 좌표 배열을 초기화합니다.
WM_PAINT 그리드 창 컨트롤에서 그리드 패턴을 그립니다.
WM_LBUTTONDOWN 사용자가 마우스 왼쪽 단추를 누를 때 커서가 그리드 창 컨트롤 내에 있는지 여부를 결정합니다. 이 경우 대화 상자 프로시저는 적절한 그리드 셀을 반전하고 사용자 지정 브러시에 대한 비트맵을 만드는 데 사용되는 비트 배열에 해당 셀의 상태를 기록합니다.
WM_COMMAND 세 개의 푸시 단추 컨트롤에 대한 입력을 처리합니다. 사용자가 테스트 패턴 단추를 클릭하면 대화 상자 프로시저가 새 사용자 지정 브러시 패턴으로 테스트 패턴 컨트롤을 그립니다. 사용자가 확인 또는 취소 단추를 클릭하면 대화 상자 프로시저가 그에 따라 작업을 수행합니다.

 

메시지 및 메시지 처리에 대한 자세한 내용은 메시지 및 메시지 큐를 참조하세요.

대화 상자 프로시저를 작성한 후 애플리케이션의 헤더 파일에 프로시저에 대한 함수 정의를 포함하고 애플리케이션의 적절한 지점에서 대화 상자 프로시저를 호출합니다.

애플리케이션의 헤더 파일에서 발췌한 다음 내용은 대화 상자 프로시저에 대한 함수 정의와 호출하는 두 함수를 보여 줍니다.

BOOL CALLBACK BrushDlgProc(HWND, UINT, WPARAM, LPARAM); 
int GetStrLngth(LPTSTR); 
DWORD RetrieveWidth(LPTSTR, int); 

마지막으로, 다음 코드는 애플리케이션의 소스 코드 파일에서 대화 상자 프로시저를 호출하는 방법을 보여 냅니다.

    DialogBox((HANDLE)GetModuleHandle(NULL), 
        (LPTSTR)"CustBrush", 
        hWnd, 
        (DLGPROC) BrushDlgProc); 

이 호출은 일반적으로 애플리케이션 메뉴에서 옵션을 선택하는 사용자에 대한 응답으로 수행됩니다.