황동준님의 윈도우 32비트 프로그래밍 06~10

  윈도우 32비트 프로그래밍 06

 안녕하세요….돌팔이 황동준입니다…

이번에도 역시 윈도우를 제어하는 예제에 대해 알아 보겠습니다. 먼저 윈도우를 다른 크기로
원하는 곳에 위치해 놓는 예제부터 알아봅시다.

윈도우를 생성할 때 CreateWindow() 함수를 사용했죠? 그 함수의 파라미터를 보면
윈도우의 생성좌표와 크기를 CW_USEDEFAULT라고 지정했을 겁니다. 이 위치와 크기를 유저가 임의로 바꿀 수 있는데 이때
MoveWindow()라는 함수를 사용하면 됩니다.

BOOL MoveWindow(
    HWND  hwnd,
    int
 x,
    int  y,
    int  cx,
    int  cy,
    BOOL
 fRepaint
   );   

두번째와 세번째 파라미터가 옮길 좌표를 의미하고 네번째와 다섯번째 파라미터가 윈도우의 크기를
의미하는 것입니다. 여섯번째 파라미터는 배경을 지울 것인지 판단하는 역할을 합니다. InvalidateRect()함수에서도 사용됐죠?

그럼 이 함수를 이용한 예제를 보도록 합시다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to create window”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    switch(mesg)
    {
        case
WM_CREATE :

            MoveWindow(hWnd, 0, 0, 300, 150,
TRUE);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

위 예제는 윈도우가 생성될 때 그 위치를 (0, 0)으로 크기를 300, 150으로 바꾸는
예제입니다. 뭐 그렇게 다시 설명할 부분은 없는 것 같군요. 그렇죠? 너무 쉽네요.

자 이번에는 윈도우의 크기를 고정하는 예제를 보도록 합시다. 일반적으로 윈도우를
생성하면 유저가 그 크기를 임의로 마우스로 조정할수 있는데 이것을 못하게 할 수 있습니다.

어떻게 못하게 하는지 알려면 우선 메시지 하나를 알아야 합니다. 유저가 윈도우의 크기나
위치를 바꾸려면 그 때에 WM_GETMINMAXINFO라는 메시지가 발생되는데 이 메시지를 처리하는 부분에 그 윈도우의 크기를 제한하는 루틴을
넣어주면 윈도우의 크기를 고정시킬 수 있습니다.

그럼 먼저 소스를 보도록 합시다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to create window”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    switch(mesg)
    {
        case
WM_CREATE :

            MoveWindow(hWnd, 100, 100, 300, 150,
TRUE);
            return FALSE;

        case WM_GETMINMAXINFO :

            ((MINMAXINFO
*)lParam)->ptMaxTrackSize.x = 300;
            ((MINMAXINFO
*)lParam)->ptMaxTrackSize.y = 150;
            ((MINMAXINFO
*)lParam)->ptMinTrackSize.x = 300;
            ((MINMAXINFO
*)lParam)->ptMinTrackSize.y = 150;
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

위 예제는 윈도우를 300, 150 크기로 생성하고 그 크기를 변경하지 못하게 하는
예제입니다. 자 그러면 실제적으로 WM_GETMINMAXINFO 메시지 처리 부분을 보도록 합시다.

case WM_GETMINMAXINFO :

    ((MINMAXINFO *)lParam)->ptMaxTrackSize.x =
300;
    ((MINMAXINFO *)lParam)->ptMaxTrackSize.y =
150;
    ((MINMAXINFO *)lParam)->ptMinTrackSize.x =
300;
    ((MINMAXINFO *)lParam)->ptMinTrackSize.y = 150;
    return
FALSE;

UINT형인 mesg에 주 메시지가 들어가고 wParam이나 lParam에 부수적인 메시지가
들어간다고 제일 처음부분에서 설명 드렸을 겁니다. 이 메시지를 처리할때는 위에서 보듯이 lParam이라는 메시지를 사용하는 군요.

WM_GETMINMAXINFO 메시지가 발생됐을때 MINMAXINFO라는 구조체 형식으로
lParam에 값을 채워주면 그 값에 의해서 윈도우의 크기를 제한할수 있습니다. 아래는 이 구조체의 원형입니다.

typedef struct tagMINMAXINFO {  // mmi
 
    POINT ptReserved;         
    POINT ptMaxSize;
         
    POINT ptMaxPosition;      
    POINT ptMinTrackSize;
    
    POINT ptMaxTrackSize;     
} MINMAXINFO;

POINT 자료형은 x, y를 맴버로 가지는 구조체입니다.

우리가 위 맴버중 사용할것은 네번째, 다섯번째 맴버인데 ptMinTrackSize의 x,
y에 값을 넣어주면 윈도우의 최소 크기를 지정하게 되는 것입니다. ptMaxTrackSize의 x, y에 값을 넣어주면 윈도우의 최대
크기이고요. 윈도우의 최소 크기와 최대크기를 같게 만들어 주었으니 윈도우의 크기가 변하지 않겠죠? 간단하네요.

자 이번에는 윈도우의 배경색을 바꾸는 예제를 알아 보도록 합시다. 어! 이거 앞 부분에 이미
했죠? 그런데 앞부분에 한 것은 아주 단순한 색으로 윈도우의 색을 바꾼 것에 불가합니다. 실제로 유저가 임의로 RGB()값으로 배경색을 바꾸려면
앞에서 배운 방법으로는 불가능하죠. 그렇다고 앞 부분에서 배운 SetClassLong()이라는 함수를 사용하지 않고 바꾸는 것은 아닙니다. 앞
부분에서 어느정도 했기 때문에 그렇게 크게 어려운 부분은 없을 겁니다.

우선 원하는 색깔로 배경색을 바꾸려면 SetClassLong()함수의 파라미터로 들어가는
새로운 색깔 지정부분에 맞는 형식으로 색을 만들어야 하는데 이 때 CreateSolidBrush()함수를 사용합니다.

HBRUSH CreateSolidBrush(
    COLORREF
 crColor
   );   

파라미터로 들어가는 색의 형식으로 브러쉬 핸들을 리턴하는 함수입니다. 자세한 것은 그래픽
부분에서 다시 언급하겠습니다. 이 함수를 이용해서 생성한 브러쉬 핸들을 사용하고 난 후에는 반드시 그 핸들을 없애 주어야 합니다.
이때DeleteObject라는 함수를 사용합니다.

BOOL DeleteObject(
    HGDIOBJ  hObject
   );
  

자세한 것은 그래픽 부분에서 다룰테니 일단은 어떻게 구현했는지 봅시다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to create window”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HBRUSH hBrush;

    switch(mesg)
    {
        case WM_CREATE
:

            hBrush = CreateSolidBrush(RGB(0, 0,
125));
            SetClassLong(hWnd, GCL_HBRBACKGROUND,
(long)hBrush);
            DeleteObject(hBrush);
            InvalidateRect(hWnd,
NULL, FALSE);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

위 예제는 파란색 계통의 배경색을 가진 윈도우를 생성하는 예제입니다. RGB를 어떻게
조합하는지는 다 알고 있겠죠?

RGB(0, 0, 0)은 검정색이고 RGB(255, 255, 255)은 흰색이구요.
RGB(255, 0, 0)은 빨간색이 되겠고, RGB(0, 255, 0)은 녹색, RGB(0, 0, 255)는 파란색입니다.

R은 빨간색을 의미하고 G는 녹색을 B는 파란색을 의미합니다. 세 색깔을 조합해서 색을
만들면 됩니다.

case WM_CREATE :

    hBrush = CreateSolidBrush(RGB(0, 0,
125));
    SetClassLong(hWnd, GCL_HBRBACKGROUND,
(long)hBrush);
    DeleteObject(hBrush);
    InvalidateRect(hWnd, NULL,
FALSE);
    return FALSE;

위 부분이 실제적으로 배경색을 파란색 계통으로 바꾸는 부분인데 함수 두개 추가된 것 이외는
그렇게 크게 달라진 부분은 없죠?

자 오늘 강좌는 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 07

안녕하세요……돌팔이 황동준입니다….

이번에는 유저가 그린 그림을 아이콘과 커서로 사용하는 방법에 대해 알아 보겠습니다. 그림
그리는게 어렵지 구현하는 것은 어렵지 않습니다.

우선 리소스 파일에 대해 알아야 합니다.

리소스 파일은 윈도우즈에서 사용하는 여러가지 자료들을 모아서 정의 해 놓은 것을 의미합니다.
메뉴나 대화상자, 또 비트맵, 아이콘등을 이곳에 정의해 놓죠. 우리가 그린 그림을 아이콘과 커서로 사용하려면 그 그림에 대한 정의를 이 곳에서
해주어야 합니다.자 그러면 먼저 우리가 사용할 아이콘과 커서를 그려 봅시다.

통합 환경에서 File메뉴의 New를 선택하시기 바랍니다. 그러면 대화상자가 생성되죠?
아래부분을 보세요. Icon File과 Cursor File이 있을 겁니다. 그것을 선택하면 그림을 그릴 수 있는 상태로 환경이 바뀌는데
그곳에서 그림을 그리면 됩니다. 다 그렸으면 원하는 파일이름으로 저장하시기 바랍니다. 저장할 곳은 프로그램 파일이 있는 곳이여야 겠죠? 여기서
주의할 점이 있습니다.

컴파일을 할 때 꼭 이 리소스 파일을 프로젝트 파일에 포함시켜 주어야 한다는 거죠.
추가시키는 방법은 Insert 메뉴의 Files into Project를 선택해서 하면 됩니다. 아! 한가지 또 빼먹었군요. 리소스 파일의
확장자는 rc이어야 한다는 것입니다.

자 그럼 실제적으로 소스를 보도록 합시다.

아래는 리소스 파일의 소스(test.rc)입니다.

#include <windows.h>

MyIcon      ICON        “my.ico”
MyCursor
   CURSOR      “my.cur”

아래는 프로그램 소스(test.c)입니다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to create window”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(hInstance,
“MyIcon”);
        WndClass.hCursor = LoadCursor(hInstance,
“MyCursor”);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    switch(mesg)
    {
        case
WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

어때요? 정말로 아이콘과 커서가 그린 그림으로 바뀌었죠? 자 그러면 리소스 파일을
보도록 합시다.

MyIcon      ICON        “my.ico”
MyCursor
   CURSOR      “my.cur”

뒤에 따옴표로 묶인 것이 실제 그림 파일의 이름이 되는 것입니다.

WndClass.hIcon = LoadIcon(hInstance,
“MyIcon”);
WndClass.hCursor = LoadCursor(hInstance, “MyCursor”);

클래스 등록부분에 위와 같은 형식으로 기입하면 됩니다. 간단하죠. 자 여기까지 해서 윈도우에
관련된 부분은 끝난 것 같군요.. 다음 시간에는 입출력에 대해 알아 보겠습니다.

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 08

안녕하세요…돌팔이 황동준입니다.

이번에는 윈도우의 작업영역에 문자열을 출력하는 방법에 대해 알아 보겠습니다.

먼저 출력에 대해 알아보기 전에 두가지를 알아야 합니다. 첫째로 디바이스 컨텍스트 핸들에
대해 알아야 하는데 이것은 문자를 출력하거나 그림을 그릴 때 사용합니다. 쉽게 말해서 출력 핸들을 윈도우로부터 가지고 와서 이 핸들을 이용해서
출력을 하는거죠. 윈도우에 대한 출력 함수를 보면 대부분 이 디바이스 컨텍스트 핸들을 파라미터로 요구합니다. 그렇다면 이 핸들을 어떻게
윈도우로부터 얻을 수 있을까요? 물론 얻을 수 있는 함수가 있습니다.

HDC BeginPaint(
    HWND
 hwnd,
    LPPAINTSTRUCT  lpps
   );

위 함수를 이용해서 디바이스 컨텍스트 핸들을 얻을 수 있습니다. 리턴값을 보면 HDC라고
되어 있죠. 바로 디바이스 컨텍스트 핸들의 자료형입니다. 두번째 파라미터에 보면 못보던 자료형이 하나 있을 겁니다.

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

구체적으로 각 멤버가 어떤 역할을 하는 지는 알 필요 없습니다. 단지 작업영역의 좌표를
기억하고 있다가 나중에 필요할 때 이 값을 참조한다는 정도만 알고 있으면 됩니다.

BeginPaint() 함수를 이용해서 디바이스 컨텍스트 핸들을 얻은 후 그 핸들을 이용해서
출력을 다 하면 다시 핸들을 반환해야 하는데 이때에는 EndPaint()함수를 사용합니다.

BOOL EndPaint(
    HWND  hwnd,
    CONST
PAINTSTRUCT  *lpPaint
   );

꼭 주의하시기 바랍니다. 프로그램상에서 출력 루틴이 끝나면 반드시 위 함수로 핸들을 반환해야
합니다.

자 핸들을 얻는 방법을 알아보았으니 출력하는 함수에 대해 알아 봅시다.

BOOL TextOut(
    HDC  hdc,
    int
 nXStart,
    int  nYStart,
    LPCTSTR  lpString,
    int
 cbString
   );

윈도우의 작업영역에 출력을 할 때 위 함수를 이용해서 합니다. 첫번째 파라미터는 얻은
디바이스 컨텍스트 핸들을 의미하고 두번째, 세번째 파라미터는 출력될 좌표를 그리고 네번째 파라미터는 문자열, 다섯번째 파라미터는 문자열의 길이를
의미합니다.

위 함수말고도 출력하는 다른 함수도 있는데 그것은 DrawText()라는 함수입니다. 이
함수는 지정된 좌표에 문자열을 출력하는 것이 아니라 지정해준 사각 좌표의 원하는 위치에 문자열을 출력하는 것입니다. 쉽게 예를 들어서 작업영역에
임의의 사각좌표를 지정해준 다음 그 사각좌표의 가운데 또는 위 오른쪽 위치등에 문자열을 출력할 수 있다는 것입니다.

int DrawText(
    HDC  hdc,
    LPCTSTR
 lpszStr,
    int  cchStr,
    LPRECT  lprc,
    UINT  wFormat
   );
  

첫번째 파라미터는 디바이스 컨텍스트 핸들을 의미하고 두번째 파라미터는 출력할 문자열, 세번째
파라미터는 문자열의 길이, 네번째 파라미터는 사각좌표, 다섯번째 파라미터는 예약되어 있는 문자열을 지정하는데 사각좌표의 구체적인위치를
의미합니다. 이 안에 지정될 수 있는 예약어는 다음과 같습니다.

DT_BOTTOM       사각좌표의 아래부분을 의미합니다.
DT_CENTER
      사각좌표의 가로방향  가운데를 의미합니다.
DT_LEFT         사각좌표의 왼쪽 부분을 의미합니다.
DT_RIGHT
       사각좌표의 오른쪽 부분을 의미합니다.
DT_SINGLELINE   한 라인에 출력함을 의미합니다.
DT_TOP
         사각좌표의 윗 부분을 의미합니다.
DT_VCENTER      사각좌표의 세로방향 가운데를 의미합니다.

자 그럼 예제 소스를 보도록 합시다.

#include <windows.h>
#include
<string.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to print string”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    RECT
rect;
    PAINTSTRUCT ps;
    char szPrint[] = “This program is to print
string”;

    switch(mesg)
    {
        case WM_PAINT
:

            GetClientRect(hWnd,
&rect);
            hDC = BeginPaint(hWnd,
&ps);
            TextOut(hDC, 10, 10, szPrint,
strlen(szPrint));
            DrawText(hDC, szPrint, strlen(szPrint),
&rect,
                DT_SINGLELINE|DT_CENTER|DT_VCENTER);
            EndPaint(hWnd,
&ps);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

위 소스를 보면 못보던 메시지가 하나 있을 겁니다. 바로 WM_PAINT라는 메시지인데 이
메시지는 윈도우를 화면에 그릴 때 발생되는 메시지입니다.

case WM_PAINT :

    GetClientRect(hWnd, &rect);
    hDC =
BeginPaint(hWnd, &ps);
    TextOut(hDC, 10, 10, szPrint,
strlen(szPrint));
    DrawText(hDC, szPrint, strlen(szPrint),
&rect,
        DT_SINGLELINE|DT_CENTER|DT_VCENTER);
    EndPaint(hWnd,
&ps);
    return FALSE;

윈도우를 화면에 그리고 바로 문자열을 작업영역에 출력하기 때문에 위 메시지하에 처리를 해 준
겁니다.

뭐 특별히 다시 설명 드릴부분은 없는것 같군요. 단지 위 예제에서는 DrawText()함수를
이용해서 출력하게 되면 작업영역의 가운데에 문자열이 출력된다는 것만 아시면 됩니다.

자 오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 09

안녕하세요….돌팔이 황동준입니다.

이번에는 입력부분에 대해 알아보도록 합시다. 앞 부분에서 이미 약간 언급을 했지만 용어
하나를 잘 기억하고 있어야 합니다. 바로 커서와 캐럿이라는 용어인데 커서는 마우스의 화살표 모양을 의미하는 것이고 입력을 받기 위해서 깜박이는
것을 캐럿이라고 합니다. 도스에서는 바로 이 캐럿을 커서라고 정의했을 겁니다. 자 먼저 디바이스 컨텍스트 핸들을 얻는 방법부터 알아봅시다. 어!
위에서 이미 했는데 또 하나라고 생각할지도 모르지만 좀 다릅니다. WM_PAINT 메시지하에서 출력을 하려면 BeginPaint() 함수를
이용해서 핸들을 얻으면 되지만 다른 메시지하에서 출력을 하기 위해 핸들을 얻으려면 GetDC()라는 함수를 이용해서 얻어야합니다.

HDC GetDC(
    HWND  hwnd
   );   

핸들을 반환할때에는 ReleaseDC() 함수를 사용하면 됩니다.

int ReleaseDC(
    HWND  hwnd,
    HDC
 hdc
   );

우리는 출력하는 함수에 대해 이미 위에서 배웠을 겁니다. 추가로 폰트를 선택해서 출력하는
부분도 보도록 합시다. GetStockObject()라는 함수를 기억합니까? 한참 위에서 배웠죠? 이 함수를 이용해서 시스템 고정 폰트를 얻고
그 핸들을 디바이스 컨텍스트 핸들에 선택되게 해 주면 그 디바이스 컨텍스트 핸들을 이용해서 출력할 때 그 고정폰트로 출력됩니다.

HGDIOBJ SelectObject(
    HDC
 hdc,
    HGDIOBJ  hgdiobj
   );

어떤 객체의 핸들을 디바이스 컨텍스트 핸들에 선택되게 해주는 함수입니다. 우리는 이번
예제에서 폰트 객체를 사용할 겁니다.

BOOL GetTextMetrics(
    HDC  hdc,   // handle
of device context
    LPTEXTMETRIC  lptm  // address of text metrics
structure
   );

위 함수는 우리가 받은 디바이스 컨텍스트 핸들을 이용해서 문자(폰트)에 대한 정보를 얻을 때
사용합니다. 입력을 받는 예제에 대해서 알아 보는데 이 함수가 왜 필요할까요?

이렇게 생각하면 간단합니다. 좌표 (0, 0)에 캐럿이 깜박이고 있는데 여기서 우리가 A라는
문자를 입력했다고 합시다. 그러면 A라는 문자가 그 좌표에 찍혀야겠죠? 그리고 캐럿은 다음 좌표로 이동해야 하구요. 우리가 윈도우에서 사용하는
좌표는 도스에서의 그래픽 좌표와 같습니다. A라는 문자가 찍히고 난 후의 그 다음 좌표가 (1, 0)이아니라  A라는 문자의 가로 넓이 만큼
X좌표를 이동해 주어야 하는 것입니다. 그렇다면 A라는 글자의 가로 넓이를 알아야 하는데 이때 위 함수를 이용해서 넓이를 알아낼 수 있습니다.
Y좌표도 그런 식으로 계산해 주어야 합니다. 다음은 두번째 파라미터의 원형입니다.

typedef struct _TEXTMETRIC { // tm
    LONG
tmHeight;
    LONG tmAscent;
    LONG tmDescent;
    LONG
tmInternalLeading;
    LONG tmExternalLeading;
    LONG
tmAveCharWidth;
    LONG tmMaxCharWidth;
    LONG tmWeight;
    LONG
tmOverhang;
    LONG tmDigitizedAspectX;
    LONG
tmDigitizedAspectY;
    BCHAR tmFirstChar;
    BCHAR
tmLastChar;
    BCHAR tmDefaultChar;
    BCHAR tmBreakChar;
    BYTE
tmItalic;
    BYTE tmUnderlined;
    BYTE tmStruckOut;
    BYTE
tmPitchAndFamily;
    BYTE tmCharSet;

} TEXTMETRIC;

tmHeight가 선택된 문자의 높이를 저장할 멤버이고 tmAveCharWidth가 넓이를
저장할 멤버를 의미합니다.

캐럿이 원하는 좌표에 깜박이려면 먼저 캐럿을 생성해 주어야 하는데 캐럿을 생성할 때는 아래
함수를 이용해서 하면 됩니다.

BOOL CreateCaret(
    HWND  hwnd,
    HBITMAP
 hbmp,
    int  nWidth,
    int  nHeight
   );

두번째 파라미터에 보면 비트맵 핸들을 지정하게 되어 있는데 이 값을 NULL로 해주면 그냥
일반적인 캐럿 모양을 생성하고 그림 핸들을 지정해 주면 그 그림의 모양으로 캐럿의 모양이 결정됩니다. 세번째, 네번째 파라미터는 캐럿의 크기를
의미하는 것입니다.

캐럿을 원하는 좌표에 놓을 때에는 아래 함수를 사용하면 됩니다.

BOOL SetCaretPos(
    int  nX,
    int
 nY
   );   

파라미터 차례로 x, y좌표를 의미합니다.

실제적으로 생성하고 어느 곳에 위치한 캐럿을 눈에 보이려면 아래 함수를 사용합니다.

BOOL ShowCaret(
    HWND  hwnd
   );

캐럿을 보이지 않게 하려면 아래 함수를 이용하면 되구요.

BOOL HideCaret(
    HWND  hwnd
   );

자 대략적으로 이번 예제에서 사용할 함수에 대해 알아 보았는데 그러면 실제로 소스를 보도록
합시다. 아래 예제는 간단한 에디터를 구현한것인데 화면 스크롤같은 것은 처리하지 않은 것입니다. 단지 유저가 입력하는 문자를 화면에 보여주기만
합니다.

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to input string”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    TEXTMETRIC
tm;
    char cChar;
    static int cxChar, cyChar, nX, nY;

    switch(mesg)
    {
        case WM_CREATE
:

            nX = nY = 0;
            hDC =
GetDC(hWnd);
            SelectObject(hDC,
GetStockObject(SYSTEM_FIXED_FONT));
            GetTextMetrics(hDC,
&tm);
            ReleaseDC(hWnd, hDC);
            cxChar =
tm.tmAveCharWidth;
            cyChar = tm.tmHeight;
            return
FALSE;

        case WM_SETFOCUS :

            CreateCaret(hWnd, NULL, cxChar,
cyChar);
            SetCaretPos(cxChar*nX,
cyChar*nY);
            ShowCaret(hWnd);
            return FALSE;

        case WM_KILLFOCUS :

            HideCaret(hWnd);
            DestroyCaret();
            return
FALSE;

        case WM_CHAR :

            HideCaret(hWnd);
            hDC =
GetDC(hWnd);
            if(LOWORD(wParam) !=
'r')
            {
                cChar =
(char)wParam;
                TextOut(hDC, cxChar*nX, cyChar*nY, &cChar,
1);
                nX++;
            }
            ReleaseDC(hWnd,
hDC);
            SetCaretPos(cxChar*nX,
cyChar*nY);
            ShowCaret(hWnd);
            return FALSE;

        case WM_KEYDOWN :

            if(LOWORD(wParam) ==
VK_RETURN)
            {
                HideCaret(hWnd);
                nY++;
                nX
= 0;
                SetCaretPos(cxChar*nX,
cyChar*nY);
                ShowCaret(hWnd);
            }
            return
FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

자 그러면 구체적으로 각 메시지에서 어떤 직업들을 하는지 알아 봅시다. 먼저 윈도우가 생성될
때 입니다.

case WM_CREATE :

    nX = nY = 0;

초기 좌표를 (0, 0)으로 초기화 하는 작업입니다.

    hDC = GetDC(hWnd);
    SelectObject(hDC,
GetStockObject(SYSTEM_FIXED_FONT));
    GetTextMetrics(hDC,
&tm);
    ReleaseDC(hWnd, hDC);
    cxChar =
tm.tmAveCharWidth;
    cyChar = tm.tmHeight;
    return FALSE;

디바이스 컨텍스트 핸들을 얻어 고정 폰트를 선택하고 그 고정 폰트에 대한 문자 길이와 넓이를
얻는 과정입니다.

case WM_SETFOCUS :

흠 못보던 메시지가 있군요. 위 메시지는 윈도우가 입력 포커스를 얻었다는 것을 알리는
메시지입니다. 메시지를 생성하고 보이는 루틴을 이 이하에 작성해주면 되죠.

    CreateCaret(hWnd, NULL, cxChar,
cyChar);
    SetCaretPos(cxChar*nX,
cyChar*nY);
    ShowCaret(hWnd);
    return FALSE;

캐럿을 현재 고정 폰트의 크기만큼 생성하고 해당 좌표에 위치시켜 보이게 하는 작업을 하고
있습니다.

case WM_KILLFOCUS :

윈도우가 입력 포커스를 잃어 버렸을 때 위 메시지가 발생됩니다.

    HideCaret(hWnd);
    DestroyCaret();
    return
FALSE;

캐럿을 보이지 않게 하고 없애는 구문이 들어가 있군요. DestroyCaret()함수는 위
설명에서 하지 않았습니다. 사용방법은 위와 같습니다.

case WM_CHAR :

자 이번에는 중요한 메시지에 대해 알아 봅시다. WM_CHAR 메시지는 유저가 시스템 키를
제외한 문자키를 눌렀을 때 발생하는 메시지입니다. 예를들어서 유저가 A키를 누르거나 숫자키 8을 눌렀을 때 이 메시지가 발생되는거죠. 그러면
구체적으로 그 눌린 키가 어떤 것인지 어떻게 알 수 있을까요? 그 구체적인 키값은 wParam 메시지에 들어가게 되는 것입니다.

    HideCaret(hWnd);
    hDC =
GetDC(hWnd);
    if(LOWORD(wParam) != 'r')
    {
        cChar =
(char)wParam;
        TextOut(hDC, cxChar*nX, cyChar*nY, &cChar,
1);
        nX++;
    }

눌린키값을 화면에 출력해주는 구문입니다. 그렇게 특별한 것은 없고 단지 조건문을 잘 보기
바랍니다. 한번 위 조건문을 사용하지 않고 프로그램을 컴파일해서 실행시켜 보면 왜 위와 같은 처리 작업이 필요한지 알 수 있을 겁니다.

    ReleaseDC(hWnd,
hDC);
    SetCaretPos(cxChar*nX,
cyChar*nY);
    ShowCaret(hWnd);
    return FALSE;

문자를 출력했으니 그 다음 좌표로 캐럿을 이동해야 겠죠? 바로 그 작업입니다.

case WM_KEYDOWN :

위에서도 몇번 언급을 했지만 일반키외에 특수키가 눌리면 WM_KEYDOWN이라는 메시지가
발생됩니다. 구체적으로 어떤 특수키인지는 wParam에 저장되죠. 특수키를 구분할 때에는 윈도우에 예약되어 있는 값으로 구분하는데 그 값은
아래에 정리해 두었습니다.

    if(LOWORD(wParam) ==
VK_RETURN)
    {
        HideCaret(hWnd);
        nY++;
        nX =
0;
        SetCaretPos(cxChar*nX,
cyChar*nY);
        ShowCaret(hWnd);
    }
    return FALSE;

Enter키가 눌리면 Y좌표를 증가하고 X좌표를 0으로 해주는 작업입니다. 물론 캐럿의
위치도 바뀌어야 겠죠.

VK_CANCEL       Ctrl+Break
VK_BACK         백
스페이스
VK_TAB          탭키
VK_RETURN       Enter키
VK_SHIFT
       Shift키
VK_CONTROL      Ctrl키
VK_MENU         Alt키
VK_PAUSE
       Pause키
VK_CAPITAL      Caps Lock키
VK_ESCAPE       Esc키
VK_SPACE
       Space키
VK_PRIOR        PageUp키
VK_NEXT         PageDown키
VK_END
         End키
VK_HOME         Hone키
VK_LEFT         방향키 왼쪽
VK_RIGHT
       방향키 오른쪽
VK_UP           방향키 위
VK_DOWN         방향키 아래
VK_INSERT
      Insert키
VK_DELETE       Delete키
VK_F1
          F1키
.
.
VK_F12          F12키

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~

 

  윈도우 32비트 프로그래밍 10

안녕하세요…돌팔이 황동준입니다..

이번에는 출력에 대한 부분을 좀더 보도록 하죠.. 전부 세가지 예제를 들어서 설명드릴
것입니다. 많이 사용되는 것이니 잘 알아 두시기 바랍니다.

제일 첫번째 예제로 우리는 출력할 때 정렬 기준을 오른쪽으로 하게 하는 방법에 대해 알아
보겠습니다. 아마 여러분들 워드 프로세서 사용하시면서 문서의 정렬 방식을 왼쪽, 가운데, 오른쪽으로 하는 기능을 사용해 보셨을 겁니다. 사실
구현은 간단하죠. 함수 하나만 알면 되니깐요.

UINT SetTextAlign(
    HDC  hdc,
    UINT
 fMode
   );   

두번째 파라미터에 어떤 값을 넣어주느냐에 따라 정렬방식이 바뀝니다. 어떤 파라미터들이 들어갈
수 있는지 알아 볼까요?

TA_BOTTOM   문자열의 사각 좌표 아래 부분이 정렬 기준이 됩니다.
TA_TOP
     문자열의 사각 좌표 위 부분이 정렬 기준이 됩니다.
TA_CENTER   문자열의 사각 좌표 가운데 부분이 정렬 기준이
됩니다.
TA_LEFT     문자열의 사각 좌표 왼쪽 부분이 정렬 기준이 됩니다.
TA_RIGHT    문자열웳 사각 좌표 오른쪽
부분이 정렬 기준이 됩니다.

자 그러면 이 함수를 이용해서 출력되는 문자열을 오른쪽으로 정렬하는 예제를 보도록
합시다.

#include <windows.h>
#include
<string.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to print string”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    PAINTSTRUCT
ps;
    static int x, y;

    switch(mesg)
    {
        case WM_CREATE
:

            x = 100;
            y =
10;
            return FALSE;

        case WM_PAINT :

            hDC = BeginPaint(hWnd,
&ps);
            SetTextAlign(hDC,
TA_TOP|TA_RIGHT);
            TextOut(hDC, x, y, “This”, 4);
            y
+= 20;
            TextOut(hDC, x, y, “is”, 2);
            y +=
20;
            TextOut(hDC, x, y, “a”, 1);
            y +=
20;
            TextOut(hDC, x, y, “test”, 4);
            EndPaint(hWnd,
&ps);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

자 프로그램 내용을 살펴 보도록 합시다.

case WM_CREATE :

    x = 100;
    y = 10;
    return
FALSE;

먼저 윈도우가 생성될때 문자열을 출력할 위치를 기억하고 있는 변수값을 초기화하는 작업을 하고
있습니다.

case WM_PAINT :

    hDC = BeginPaint(hWnd,
&ps);
    SetTextAlign(hDC, TA_TOP|TA_RIGHT);

오른쪽 정렬방식을 사용하기 위해서 위 함수를 사용했네요.

    TextOut(hDC, x, y, “This”, 4);
    y +=
20;
    TextOut(hDC, x, y, “is”, 2);
    y += 20;
    TextOut(hDC, x,
y, “a”, 1);
    y += 20;
    TextOut(hDC, x, y, “test”,
4);
    EndPaint(hWnd, &ps);
    return FALSE;

프로그램을 실행시켜 보면 알겠지만 X좌표가 전부 같은데도 정렬되는 기준은 왼쪽으로 되어 있지
않고 오른쪽으로 됨을 알수 있습니다. 함수 하나만 알면 되는 문제니 크게 어려운 점은 없을 겁니다.

이번에는 두번째 예제로 글자색과 배경색을 바꾸어서 출력하는 예제를 보도록 하겠습니다.
이번에도 함수 두개만 알면 됩니다. 사용방법도 간단하죠.

COLORREF SetTextColor(
    HDC
 hdc,
    COLORREF  crColor
   );

글자색을 바꿀때 사용하는 함수입니다. 두번째 파라미터로 바꿀색을 RGB로 조합해주면
됩니다.

COLORREF SetBkColor(
    HDC
 hdc,
    COLORREF  crColor
   );

배경색을 바꿀때 사용하는 함수입니다. 두번째 파라미터로 바꿀 색을 RGB로 조합해주면
됩니다. 함수 이름만 다르지 글자색 바꾸는 함수와 사용방법이 같죠.

그러면 배경색을 파란색으로 하고 글자색을 흰색으로 해서 출력하는 예제를 봅시다.

#include <windows.h>
#include
<string.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to print string”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    PAINTSTRUCT
ps;
    static int x, y;

    switch(mesg)
    {
        case WM_CREATE
:

            x = 100;
            y =
10;
            return FALSE;

        case WM_PAINT :

            hDC = BeginPaint(hWnd,
&ps);
            SetTextAlign(hDC,
TA_TOP|TA_RIGHT);
            SetTextColor(hDC, RGB(255, 255,
255));
            SetBkColor(hDC, RGB(0, 0,
125));
            TextOut(hDC, x, y, “This”, 4);
            y +=
20;
            TextOut(hDC, x, y, “is”, 2);
            y +=
20;
            TextOut(hDC, x, y, “a”, 1);
            y +=
20;
            TextOut(hDC, x, y, “test”, 4);
            EndPaint(hWnd,
&ps);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

case WM_PAINT :

    hDC = BeginPaint(hWnd,
&ps);
    SetTextAlign(hDC, TA_TOP|TA_RIGHT);
    SetTextColor(hDC,
RGB(255, 255, 255));
    SetBkColor(hDC, RGB(0, 0, 125));

글자색을 흰색으로 하고 배경색을 파란색으로 설정하는 구문입니다.앞으로 이 디바이스 컨텍스트
핸들을 가지고 출력하게 되면 글자색은 파란색이고 배경색은 흰색으로 찍히게 됩니다.

    TextOut(hDC, x, y, “This”, 4);
    y +=
20;
    TextOut(hDC, x, y, “is”, 2);
    y += 20;
    TextOut(hDC, x,
y, “a”, 1);
    y += 20;
    TextOut(hDC, x, y, “test”,
4);
    EndPaint(hWnd, &ps);
    return FALSE;

마지막 예제로 배경 모드에 관한 예제에 대해 알아 보겠습니다. 배경모드는 크게
두가지로 나눌 수 있습니다. 예를 들어서 설명드릴까요? 만약에 윈도우의 작업영역에 그림이 출력되어 있다고 합시다. 그리고 그 위에 test라는
문자열을 출력하게 되면 어떻게 될까요? 기본적으로 윈도우에 문자열을 출력하게 되면 글자색은 검정색이고 배경색은 흰색이기 때문에 문자열이 출력된
test전체 영역은 하얀색 배경색을 가지게 됩니다. 즉 다시 말하면 문자열이 출력된 사각 영역 부분은 그림을 가리게 되는 것입니다. 이게
기본적인 배경모드입니다. 그러나 이 배경모드를 다른 하나로 바꾼다면 뒷 배경에 영향을 주지 않고 글자를 출력할 수 있습니다.

이 때 아래의 함수를 사용해서 배경모드를 바꿀 수 있습니다.

int SetBkMode(
    HDC  hdc,
    int
 iBkMode
   );   

두번째 파라미터로 어떤 값을 지정하느냐에 따라 배경모드를 기본모드로 또는 배경에 영향을 주지
않는 모드로 전환할 수 있습니다. 아래는 두번째 파라미터에 들어갈 수 있는 예약어입니다.

OPAQUE          기본적으로 세팅되어 있는
배경모드입니다.
TRANSPARENT     배경에 영향을 주지 않는 세팅모드입니다.

자 그러면 간단하게 예제를 들어서 이해해 보도록 합시다.

#include <windows.h>
#include
<string.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM);

int WINAPI WinMain
(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{

        HWND hWnd;
        MSG
msg;
        WNDCLASS WndClass;
        char szAppName[] = “This program
is to print string”;

        WndClass.style =
NULL;
        WndClass.lpfnWndProc = WndProc;
        WndClass.cbClsExtra
= 0;
        WndClass.cbWndExtra = 0;
        WndClass.hInstance =
hInstance;
        WndClass.hIcon = LoadIcon(NULL,
IDI_APPLICATION);
        WndClass.hCursor = LoadCursor(NULL,
IDC_ARROW);
        WndClass.hbrBackground =
GetStockObject(WHITE_BRUSH);
        WndClass.lpszMenuName =
NULL;
        WndClass.lpszClassName =
szAppName;
        if(!RegisterClass(&WndClass)) return NULL;

        hWnd =
CreateWindow(
                szAppName,
                szAppName,
                WS_OVERLAPPEDWINDOW,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                CW_USEDEFAULT,
                NULL,
                NULL,
                hInstance,
                NULL
        );

        ShowWindow(hWnd,
nCmdShow);
        UpdateWindow(hWnd);

        while(GetMessage(&msg, NULL, 0,
0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        return
msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT mesg,
WPARAM wParam, LPARAM lParam)
{
    HDC hDC;
    PAINTSTRUCT ps;

    switch(mesg)
    {
        case WM_PAINT
:

            hDC = BeginPaint(hWnd,
&ps);
            SelectObject(hDC,
GetStockObject(SYSTEM_FIXED_FONT));
            SetTextColor(hDC, RGB(255,
255, 255));
            SetBkColor(hDC, RGB(0, 0,
125));
            TextOut(hDC, 10, 10, “This is a test”,
14);
            TextOut(hDC, 10, 30, ”              “,
14);
            SetTextColor(hDC, RGB(255, 255,
255));
            SetBkColor(hDC, RGB(0, 0,
0));
            SetBkMode(hDC, TRANSPARENT);
            TextOut(hDC, 10,
30, “This is a test”, 14);
            EndPaint(hWnd,
&ps);
            return FALSE;

        case WM_DESTROY :

            PostQuitMessage(0);
            return
FALSE;
    }
    return DefWindowProc(hWnd, mesg, wParam,
lParam);
}

자 그러면 실제적으로 출력하는 루틴을 보도록 합시다.

case WM_PAINT :

    hDC = BeginPaint(hWnd,
&ps);
    SelectObject(hDC,
GetStockObject(SYSTEM_FIXED_FONT));
    SetTextColor(hDC, RGB(255, 255,
255));
    SetBkColor(hDC, RGB(0, 0, 125));
    TextOut(hDC, 10, 10, “This
is a test”, 14);

좌표 (10, 10)에 파란색의 배경, 흰색의 글자를 갖는 문자열을 출력하는군요.

    TextOut(hDC, 10, 30, ”              “, 14);

좌표 (10, 30)에 파란색의 배경, 흰색의 글자를 갖는 문자열을 출력하는데 출력하는데
문자열이 없으니 그냥 파란색으로 칠해지기만 하겠죠?

    SetTextColor(hDC, RGB(255, 255,
255));
    SetBkColor(hDC, RGB(0, 0, 0));

배경색을 바꾸었습니다.

    SetBkMode(hDC, TRANSPARENT);

배경 모드를 배경을 지우지 않는 것으로 바꾸었네요.

    TextOut(hDC, 10, 30, “This is a test”, 14);

위와 똑같은 좌표에 문자열을 출력하고 있습니다. 정상적으로 배경 모드를 바꾸지 않고
기본적으로 했다면 분명히 흰색 글자에 검정색 배경을 가진 문자열이 출력되었을텐데 배경모드를 바꾸었기 때문에 뒷 배경에 영향을 주지
않습니다.
즉 이 배경색을 바꾸기 전에 윈도우에 출력되어 있는 파란색 부분이 그대로 있는 것입니다. 쉽게 얘기해서 글자색은 흰색 배경색은
파란색으로 찍힌 문자열을 눈으로 확인할 수 있을 겁니다. 이해하기 어렵지 않죠?

    EndPaint(hWnd, &ps);
    return
FALSE;

오늘 알아본 세가지 예제는 그렇게 크게 어려운 것이 없을 겁니다. 함수만 알면
되는거죠 뭐.

오늘은 여기까지
끝~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

zemna

Programmer/Web/Mobile/Desktop

You may also like...

Leave a Reply