본문 바로가기

Windows/_Windows Programming

출력하기

1. DC(Device Context)

윈도우즈는 세 가지 동적 연결 라이브러리(DLL) 로 구성되어 있는데

KERNEL : 메모리를 관리하고 프로그램을 실행시킨다.
USER : 유저 인터페이스와 윈도우를 관리한다.
GDI : 화면 처리와 그래픽을 담당한다.

윈도우즈 API 함수의 대부분은 이 세 DLL에 의해 제공된다.
특히 화면으로 출력되는 모든 글자와 그림은 GDI 를 통해야 한다.

DC(Device Context)란 출력에 필요한 '모든 정보'를 가지는 데이터 구조체이며 GDI 모듈에 의해 관리된다.(ex. 폰트, 선의 색상과 굵기, 허가된 영역에만 출력하게 하기, 출력 방법 등등)



2. 기본 출력 예제

DC를 사용하여 문자열을 출력해보자.
마우스 왼쪽 버튼(WM_LBUTTONDOWN)을 누르면 문자열이 출력되도록 하겠다.(WndProc에서 WM_LBUTTONDOWN 메시지를 처리해준다)

(윈도우 프로그램 기본틀에 수정을 하면 된다 http://dakuo.tistory.com/entry/1)

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
                                             WPARAM wParam, LPARAM lParam)
{
       HDC hdc;
       switch(iMessage)
       {
               case WM_DESTORY:
                       PostQuitMessage(0);
                       return 0;
               case WM_LBUTTONDOWN:
                        hdc = GetDC(hWnd);
                        TextOut(hdc, 100, 100, "Hacker dakuo", 15);
                        ReleaseDC(hWnd, hdc);
                        return 0;
       }
       return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}


case WM_LBUTTONDOWN:
                        hdc = GetDC(hWnd);
                        TextOut(hdc, 100, 100, "Hacker dakuo", 12);
                        ReleaseDC(hWnd, hdc);
                        return 0;

마우스 왼쪽 버튼을 누를시 100, 100 좌표에 "Hacker dakuo" 라는 문자열이 출력된다.

GetDC(hWnd) : DC 획득
TextOut(hdc, 100, 100, "Hacker dakuo", 12) : 100, 100에 12자의 "Hacker dakuo"출력
ReleaseDC(hWnd, hdc) : DC 해제



3. WM_PAINT

하지만 이렇게 출력을 하면 문제점이 발생한다.

운영체제가 개별 윈도우의 화면을 보관 및 복구해 주지 않기 때문이다. 복구(Repaint)의 책임은 프로그램에게 있다. 즉 자신의 작업영역 일부가 지워졌다면 지워진 부분을 복구해야 한다.
(참조 : 예제를 실행시킨 후 다른 윈도우로 가렸다가 드러나도록 하거나 윈도우 크기를 변경시키면 출력되어 있던 문자열이 사라진다.)

운영체제는 윈도우의 일부가 지워졌다는 사실을 WM_PAINT 메시지로 프로그램에게 알려준다. 따라서 WM_PAINT 메시지를 받을때마다 복구를 해주면 된다.

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage,
                                             WPARAM wParam, LPARAM lParam)
{
       HDC hdc;
       PAINTSTRUCT ps;
       switch(iMessage)
       {
               case WM_DESTORY:
                       PostQuitMessage(0);
                       return 0;
               case WM_PAINT:
                        hdc = BeginPaint(hWnd, ps);
                        TextOut(hdc, 100, 100, "Hacker dakuo", 12);
                        EndPaint(hWnd, &ps);
                        return 0;
       }
       return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

실행을 시켜보면 아까의 문제점이 사라진 것을 알 수 있다.
윈도우에서 화면을 보관, 복구하려면 이렇게 소스를 작성해야 한다.



4. DC를 얻는 방법

출력을 하기 위해선 반드시 있어야 하는 DC를 얻는 방법에는 두가지가 있다.

첫번째 방법은 GetDC로 얻고 ReleaseDC로 해제해 주는 것이다.

GetDC는 hWnd가 가리키는 윈도우에 적당한 DC를 만들어 그 핸들을 리턴한다.
또 DC도 메모리를 차지하므로 사용 후 ReleaseDC로 해제를 해줘야 한다.


두번째 방법은 WM_PAINT 메시지 루틴에서만 사용할수 있다.

BeginPaint 함수로 얻을 수 있으며 해제할 때는 EndPaint 함수를 사용한다.

WndProc 선두에서 PAINTSTRUCT 형의 구조체를 지역변수로 선언하고
HDC BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint);
BOOL EndPaint(HWND, hWnd, CONST PAINTSTURCT *lpPaint);

BeginPaint 함수는 윈도우 핸들과 페인트 정보 구조체를 파라미터로 요구하며
이 구조체에 필요한 정보를 리턴해준다.

typedef struct tagPAINTSTURCT
{
        HDC      hdc;
        BOOL    fErase;
        RECT    rcPaint;
        BOOL    fRestore;
        BOOL    fIncUpdate;
        BYTE    rgbReserved[16];
} PAINTSTRUCT;

앞의 세 멤버는 사용자가, 뒤에 세 멤버는 윈도우가 내부적으로 사용하므로 건드리면 안된다.



5. TextOut

도스의 printf에 해당하는 함수이다. 원형은
BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString);

첫번째 파라미터는 DC의 핸들인 hdc 이다. 이외에도 출력에 관계된 모든 함수들의 첫번째 파라미터는 hdc이다.(GetDC나 BeginPaint로 hdc가 구해져있어야 한다)

nXtart, nYStart 는 문자열이 출력될 좌표이며, lpString는 출력할 문자열 포인터이며 cbString는 출력할 문자열의 길이이다. TextOut 함수는 문자열 끝에 NULL 문자를 사용하지 않으므로 길이를 넣어줘야한다.

위에서 쓴 TextOut(hdc, 100, 100, "Hacker dakuo", 12); 을 해석 하면
"Hacker dakuo"라는 12자 문자열을 hdc에서 지정하는 정보를 사용하여 (100,100 )좌표에 출력한다.

hdc에서 지정하는 정보를 변경하면 여러가지 변화를 줄수 있다.
(hdc의 정보를 변경해주는 API들을 쓰면 된다)



6. DrawText

TextOut보다 더 기능이 많은 문자열 출력 함수로 DrawText라는 함수가 있다.

int DrawText(HDC hdc, LPCTSTR lpString, int nCount, LPRECT lpRect, UINT uFormat);

이 함수는 사각영역을 정의하여 영역 안에 문자열을 출력하며 여러 포맷을 설정할 수 있다.

윈도우에서 사각영역을 정의할 때는 RECT 구조체를 사용한다.

typedef struct _RECT
{
        LONG left;
        LONG top;
        LONG right;
        LONG bottom;
} RECT;

왼쪽 위 좌표와 오른쪽 아래의 좌표를 정의함으로써 직사각형 영역을 나타낸다.
(ex. RECT rt = {100, 100, 200, 200);

DrawText의 4번째 파라미터인 lpRect는 이 구조체의 포인터이며 문자열이 출력될 사각영역을
지정한다. 2번째는 출력할 문자열, 3번째는 출력할 문자열의 길이이며 값이 -1이면 종료 문자열로 간주한다. 5번째는 함수가 문자열을 출력할 방법을 지정하는 플래그이다.

 값  의미 
 DT_LEFT  수평 왼쪽 정렬
 DT_RIGHT  수평 오른쪽 정렬
 DT_CENTER  수평 중앙 정렬
 DT_BOTTOM  바닥에 문자열 출력
 DT_VCENTER  수직 중앙에 문자열 출력
 DT_WORDBREAK  오른쪽 끝에서 자동 개행
 DT_SINGLELINE  한 줄로 출력
 DT_NOCLIP  사각형 경계를 벗어나도 그대로 출력 



6. 그래픽 출력

그래픽 출력도 문자열 출력과 크게 다르지 않다. 다음과 같은 함수들을 사용한다.

COLORREF SetPixel(hdc, nXPos, nYPos, clrref)
DWORD MoveToEx(hdc, x, y, lpPoint)
BOOL LineTo(hdc, xEnd, yEnd)
BOOL Rectangle(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect)
BOOL Ellipse(hdc, nLeftRect, nTopRect, nRightRect, nBottomRect)

모든 GDI 함수의 첫 번째 파라미터는 DC 핸들인 hdc이다.

Setpixel 함수는 화면에 지정한 좌표에 clrref색상으로 점을 출력한다.
MoveToEx 함수는 CP를 지정한 좌표로 이동시켜 주며 이동전의 CP를 lpPoint에 대입한다.
LineTo 함수는 CP에서부터 지정한좌표까지 선을 그으며 CP를 끝점으로 이동시켜준다.
(참조 : CP는 텍스트 모드의 커서에 해당한다고 보면된다)
Rectangle 함수와 Ellipse 함수는 지정한 좌표를 대각선으로 하는 (내부를 채운)사각형을 그린다.
(Ellipse함수는 그린 사각형에 내접하는 타원을 그린다)



7. 메시지 박스

별도의 윈도우를 열어서 사용자에게 정보를 전달해 주는 장치이며 MessageBox 함수만으로 만들 수 있다.

int MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);

첫 번째 파라미터 hWnd는 메시지 박스의 부모 윈도우이다. 메시지 박스는 부모 윈도우 중앙에 나타나며 떠 있는 동안 부모 윈도우는 사용할 수 없다.
두 번째 파라미터 lpText는 메시지 박스에 출력할 문자열이다.
세 번째 파라미터 lpCapton은 메시지 박스의 타이틀 바에 나타날 제목 문자열이다.
네 번째 파라미터 uType은 메시지 박스에 어떤 종류의 버튼이 나타날 것인가를 지정하는 플래그이다.

 값  의미 
 MB_ABORTRETRYIGNORE  Abort, Retry, Ignore 버튼
 MB_OK  OK 버튼
 MB_OKCANCEL  Ok, Cancel 버튼
 MB_RETRYCANCEL  Retry, Cancel 버튼
 MB_YESNO  Yes, No 버튼
 MB_YESNOCALCEL  Yes, No, Cancel 버튼


버튼의 종류를 지정하는 값 외에 아이콘을 출력하도록 하는 플래그도 있다.
(버튼과 or 연산자로 연결할 수 있다)

 값  아이콘
 MB_ICONEXCLAMATION
 MB_ICONWARNING
 
 MB_ICONINFORMATION
 MB_ICONASTERISK
 
 MB_ICONQUESTION  
 MB_ICONSTOP
 MB_ICONERROR
 MB_ICONHAND
 
(위의 중에 아무거나 쓰면 된다)


MessageBox 함수는 리턴값으로 사용자가 누른 버튼값을 반환한다.

 값  의미
 IDABORT  Abort 버튼 누름
 IDCANCEL  Cancel 버튼 누름
 IDIGNORE  Ignore 버튼 누름
 IDNO  No 버튼 누름
 IDOK  Ok 버튼 누름
 IDRETRY  Retry 버튼 누름
 IDYES  Yes 버튼 누름



7. 메시지 비프

비프음을 내는 들리는 종류의 출력도 할 수 있다.
스피커를 통해 간단한 비프음을 출력하고자 할 때는 MessageBeep 함수를 사용한다.

BOOL MessageBeep(UINT uType);

하나의 파라미터로 어떤 종류의 음을 낼 것인지를 지정한다.

 값  의미 
 0XFFFFFFFF  PC의 스피커를 통해 음을 낸다
 MB_ICONASTERISK  Asterisk 비프음
 MB_ICONEXCLAMATION  Exclamation 비프음
 MB_ICONHAND  Hand 비프음
 MB_ICONQUESTION  Question 비프음
 MB_OK  시스템 디폴트 비프음

'Windows > _Windows Programming' 카테고리의 다른 글

타이머(Timer)  (0) 2009.12.23
입력하기  (0) 2009.12.01
윈도우 기초 프로그래밍  (0) 2009.11.27
윈도우즈(Windows) 프로그래밍의 기초  (0) 2009.11.27
.xxx 파일 만들기  (2) 2009.11.24