Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Archives
Today
Total
관리 메뉴

codingfarm

3. 문자열의 출력(TextOut, DrawText) 본문

Windows/윈도우즈 API

3. 문자열의 출력(TextOut, DrawText)

scarecrow1992 2020. 11. 19. 23:05

1. TextOut

콘솔의 printf와 대응하는 함수라 볼 수 있다.

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

docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-textouta

매개변수

매개 변수 기능
hdc DC의 핸들
nXStart 문자열이 출력될 좌표
nYStart
lpString 출력할 문자열
cbString 출력할 문자열의 길이

문자열을 출력하기 위한 여러 복잡한 정보들(정렬 등)을 DC에 지정하고 TextOut의 인자로 전달함에 주목할것

TextOut 함수는 널 종료 문자열을 인식하지 않으므로 출력할 문자열의 길이를 인수로 반드시 밝혀야 한다.

이는 사용법의 불편함도 있지만 이식성에서도 불리하다.

가령 "대한민국"은 멀티바이트에서는 8바이트 이지만, 유니코드에서는 4문자로 계산된다.

그러므로 통상 문자열 상수를 직접 출력하지 않고, 문자배열과 lstrlen 함수를 함께 사용하여 전체 문자열을 출력한다.

 

 

사용 예

TextOut(hdc, 100, 100, TEXT("Beautiful Korea"), 15);
TCHAR *str = TEXT("Beautiful Korea");
TextOut(hdc, 100, 100, str, strlen(str));

위 호출문은 "Heautiful Korea"라는 15자 길이의 문자열을 (100, 100) 좌표에 출력하라는 뜻이다.

 

문자열 변수의 선언이 귀찮으면 아래처럼 래퍼를 만들어 사용하면 된다.

void MyTextOut(HDC &hdc, int x, int y, LPCTSTR Text){
    TextOut(hdc, x, y ,Text, lstrlen(Text));
}

 

정렬

출력에 필요한 기타 정보들은 모두 DC(Device Context)에서 지정하는 정보를 사용한다.

DC의 정보를 변경하면 문자의 모양이나 크기, 색상, 정렬상태 좌표 해석 방법 등의 여러가지 변화를 줄 수 있다.

여기서는 정렬 상태를 변경하는 방법에 대해서만 알아본다.

문자열의 정렬방법을 변경하는 함수는 SetTextAlign 이라는 함수이다.

UINT SetTextAlign( HDC hdc, UINT fMode );
매개 변수 기능
hdc DC의 핸들
fMode 정렬 정보

fMode의 값은 아래와 같으며 2개 이상의 플래그를 OR로 연결하여 지정한다.

설명
TA_TOP 지정한 좌표가 상단좌표가 된다.
TA_BOTTOM 지정한 좌표가 하단 좌표가 된다.
TA_CENTER 지정한 좌표가 수평 중앙 좌표가 된다.
TA_LEFT 지정한 좌표가 수평 왼쪽 좌표가 된다.
TA_RIGHT 지정한 좌표가 수평 오른쪽 좌표가 된다.
TA_UPDATECP 지정한 좌표대신 CP를 사용하며 문자열 출력후에 CP를 변경한다.
TA_NOUPDATACP CP를 사용하지 않고 지정한 좌표를 사용하며 CP를 변경하지 않는다.

디폴트 정렬 상태는 TA_TOP|TA_LEFT이며, 지정한 좌표를 좌상단으로 하여 문자열이 출력된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("TextOut");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
 
    switch (iMessage) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        SetTextAlign(hdc, TA_CENTER);
        TextOut(hdc, 20060, TEXT("Beautiful Korea"), 15);
        TextOut(hdc, 20080, TEXT("is My"), 5);
        TextOut(hdc, 200100, TEXT("Lovely Home Country"), 19);
        EndPaint(hWnd, &ps);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

51번째 줄의 SetTextAlign의 설정 방법에 따라 출력이 달라짐을 볼 수 있다.

 

중앙정렬(TA_CENTER)

 

왼쪽정렬(TA_LEFT)

 

오른쪽정렬(TA_RIGHT)

 

만약 case WM_PAINT: 내부를 아래처럼 쓴다면 각 줄의 정렬 결과가 달라지게된다.

1
2
3
4
5
6
7
8
9
10
case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    SetTextAlign(hdc, TA_LEFT);
    TextOut(hdc, 20060, TEXT("Beautiful Korea"), 15);
    SetTextAlign(hdc, TA_CENTER);
    TextOut(hdc, 20080, TEXT("is My"), 5);
    SetTextAlign(hdc, TA_RIGHT);
    TextOut(hdc, 200100, TEXT("Lovely Home Country"), 19);
    EndPaint(hWnd, &ps);
    return 0;
cs

x = 200 좌표를 기준으로 정렬된 상태에 주목하라

 

정수나 실수의 출력은 sprintf나 wsprintf같은 함수로 서식화 하여 문자열로 만들어 출력해야 한다.

1
2
3
4
5
6
7
8
9
case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);    
    TCHAR str[128];
    int Score = 85;
    SetTextAlign(hdc, TA_LEFT);
    wsprintf(str, TEXT("현재 점수는 %d점 입니다."), Score);
    TextOut(hdc, 1010, str, lstrlen(str));
    EndPaint(hWnd, &ps);
    return 0;
cs

 

출력 및 출력에 관계되는 모든 함수의 첫번째 인수는 무조건 hdc임을 기억하라.

 


2. DrawText

TextOut은 한줄만 출력한다.

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

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

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

왼쪽위 좌표와 오른쪽 아래의 좌표를 정의함으로써 직사각형 영역을 나타낸다.

 

DrawText 함수의 원형은 아래와 같다.

int DrawText( HDC hdc, LPCTSTR lpchText, int cchText, LPRECT lprc, UINT format );
매개변수 기능
hdc DC의 핸들
lpchText 출력할 문자열
nCount 출력할 문자열의 길이
lpRect Rect 구조체
uFormat 문자열을 출력할 방법

 

uFormat에 대한 플래그 조합은 아래와 같다.

설명
DT_LEFT 수평 왼쪽 정렬한다.
DT_RIGHT 수평 오른쪽 정렬한다.
DT_CENTER 수평 중앙 정렬한다.
DT_BOTTOM 사각 영역의 바닥에 문자열을 출력한다.
DT_VCENTER 사각 영역의 수직 중앙에 문자열을 출력한다.
DT_WORDBREAK 사각영역의 오른쪽 끝에서 자동 개행되도록 한다.
DT_SINGLELINE 한줄로 출력한다.
DT_NOCLIP 사각 영역의 경계를 벗어나도 문자열을 자르지 않고 그대로 출력한다.

 

이들을 활용한 예제 코드는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <windows.h>
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("TextOut");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
 
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rt = { 100,100,400,300 };
    LPCTSTR str = TEXT("님은 갔습니다.아아 사랑하는 나의 님은 갔습니다."
        " 푸른 산빛을 깨치고 단풍나무 숲을 향하여 난 작은 길을 걸어서"
        " 차마 떨치고 갔습니다.황금의 꽃같이 굳고 빛나던 옛 맹세는"
        " 차디찬 티끌이 되어 한숨의 미풍에 날아갔습니다.");
 
    switch (iMessage) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);    
        DrawText(hdc, str, -1&rt, DT_CENTER | DT_WORDBREAK);
        EndPaint(hWnd, &ps);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

 

 

요약

  • 문자열 출력 함수는 크게 2개로 나뉘어짐
    • TextOut : 한줄만 출력, 정렬 정보는 DC에 담겨 전달받음
    • DrawText : 사각 영영을 정의하여 그 안에 문자열을 출력

 

 

 

 

'Windows > 윈도우즈 API' 카테고리의 다른 글

3. 메시지 박스 (Message Box)  (0) 2020.11.23
3. 그래픽 출력  (0) 2020.11.19
3. DC(Device Context)  (0) 2020.11.19
2. 다양한 변형  (0) 2020.11.17
2. 기본 윈도우 생성 - 윈도우 생성 과정, 메시지 루프  (0) 2020.04.27
Comments