Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

7-1. 컨트롤 - 버튼 본문

Windows/윈도우즈 API

7-1. 컨트롤 - 버튼

scarecrow1992 2021. 12. 26. 17:27

1. 버튼

CreateWindow를 함수의 원형을 다시 살펴본다.

1
2
3
4
5
6
7
8
9
10
11
12
13
void CreateWindowW(
  [in, optional]  lpClassName,
  [in, optional]  lpWindowName,
  [in]            dwStyle,
  [in]            x,
  [in]            y,
  [in]            nWidth,
  [in]            nHeight,
  [in, optional]  hWndParent,
  [in, optional]  hMenu,
  [in, optional]  hInstance,
  [in, optional]  lpParam
);
cs

우리는 윈도우를 생성하기 위해 첫번째 매개변수인 lpClassName에 registerehls WNDCLASS인스턴스의 lpszClassName 필드에 설정했던 문자열과 똑같은 값을 할당하여 Window Class를 특정하였다.

우리는 컨트롤 윈도우를 생성하기 위해 이 첫번째 매개변수인 pClassName에 OS에서 미리 생성된 윈도우 클래스의 이름을 전달한다. 버튼의 경우 TEXT("button")을 설정하면 된다.

구체적인 사용법은 가령 아래와 같다.

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
62
63
64
65
66
#include <windows.h>
#include <tchar.h>
 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Menu");
 
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(WHITE_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)
{
    switch (iMessage) {
    case WM_CREATE:
        CreateWindow(L"button", L"Click Me", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            202010025, hWnd, (HMENU)0, g_hInst, NULL);
        CreateWindow(L"button", L"Me Two", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            205010025, hWnd, (HMENU)1, g_hInst, NULL);
        return 0;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case 0:
            MessageBox(hWnd, L"First Button Clicked", L"Button", MB_OK);
            break;
        case 1:
            MessageBox(hWnd, L"Second Button Clicked", L"Button", MB_OK);
            break;
        }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

눈 여겨 볼만한 인수를 몇가지 살펴본다.

1. lpClassName : OS가 미리 등록한 WNDCLASS의 이름을 넣어준다.

2. lpWindowName : 버튼 위에 출력될 문자열

3. dwStyle : 윈도우의 속성값.
컨트롤은 차일드 윈도우 이므로 예외없이 WS_CHILD 스타일을 주어야 한다.
WS_VISIBLE 스타일을 주어야 ShowWindow 함수를 호출하지 않아도 컨트롤이 화면에 나타난다.
그러므로 컨트롤의 경우 위 2개 값은 거의 예외 없이 지정하는것이 정석이다.
이외에는 컨트롤에 따라 고유한 스타일을 추가로 지정하며, 버튼의 경우 아래와 같이 BS_ 접두어의 스타일 값이 사용된다.

스타일 속성
BS_PUSHBUTTON 푸시 버튼
BS_DEFPUSHBUTTON 디폴트 푸시 버튼
BS_CHECKBOX 체크 박스
BS_3STATE 3가지 상태를 가지는 체크 박스
BS_AUTOCEHCKBOX 자동 체크 박스
BS_AUTO3STATE 3가지 상태를 가지는 자동 체크 박스
BS_RADIOBUTTON 라디오 버튼
BS_GROUPBOX 그룹 박스

나머지 버튼 스타일은 추후 알아본다.

 

8. hWndParent 부모윈도우

컨트롤의 부모 윈도우를 지정한다. 컨트롤은 차일드이므로 반드시 부모 윈도우가 있어야 한다. 즉, 컨트롤이 화렁화될 윈도우의 핸들 값을 넣어주면된다.

자식윈도우는 항상 부모의 위쪽에 나타나며 부모와 운명을 함께한다. 즉, 부모가 최소화 되거나 숨겨지면 자식도 같이 숨겨지며, 부모가 파괴되면 자식도 같이 파괴된다.

앞서 우리는 main 윈도우의 생성시 NULL을 지정하였는데 이는 데스크탑을 부모로 한다는 뜻이다.

 

9. hMenu ; ID

main 윈도우 : 윈도우에서 사용할 메뉴의 핸들.

차일드 컨트롤 : 컨트롤 ID 지정
매개변수에 설정한 값은 버튼을 눌렀을때 WM_COMMAND 메시지를 발생시키면서 wParam 인수를 통해 보내지는 값의 종류가 된다. 이 wParam을 통해 어떤 버튼이 눌러젔는지를 알 수 있다.

윈도우의 종류에 따라 인수가 다른 역할을 수행

 

10. hInstance

이 윈도우를 만드는 인스턴스의 핸들. WinMain의 첫 번째 인수로 받은 hInstance 값을 적절히 넣는다.

 

11. lpParam

사용자 정의 데이터, MDI에서 사용하는 구조체, 일단 무시하고 NULL 지정

 

 

2. 부모와의 통신

버튼이 눌러질 경우의 처리를 알아본다.

컨트롤은 버튼이 눌러지거나 에디트에 문자열을 입력하는듯 자신에게 이벤트가 발생했을때 부모 윈도우로 통지 메시지(Notification Message)를 보내 어떤 사건이 발생했는지를 알린다. 가령 버튼을 클릭하면 WM_COMMAND 메시지를 부모 윈도우에게 보내며 이때 전달되는 정보는 아래와 같다.

인수 설명
HIWORD(wParam) 통지코드
LOWORD(wParam) 컨트롤의 ID
lParam 메시지를 보낸 차일드 윈도우의 윈도우 핸들

통지코드 : 차일드 컨트롤이 왜 메시지를 보냈는가.
버튼의 경우 통지코드는 항상 자신을 클릭했다는 의미의 BN_CLICKED 이므로 큰 의미 없지만 통지 코드가 여러개인 컨트롤은 이 값을 검사해 보아야 한다.

컨트롤의 ID : CreateWindow의 9번째 인수 hMenu 에서 지정한 정수값이며 어떤 컨트롤이 통지 메시지를 보냈는지 알려준다

 

부모 윈도우는 WM_COMMAND에서 LOWORD(wParam) 값을 조사하여 어떤 컨트롤이 눌러졌는지에 따라 적절한 처리를 한다.

WM_COMMAND 메시지는 컨트롤의 통지 메시지 뿐만 아니라 메뉴 항목, 엑셀러레이터 등의 명령을 처리하는데, 이때 컨트롤 ID, 메뉴 ID, 액셀러레이터 ID 등은 모두 LOWORD(wParam)으로 전달되므로 각 명령들끼리는 0~65535 까지의 범위에서 중복되지 않는 ID를 가져야 한다.

WM_COMMAND 메시지 처리 루틴은 일반적으로 아래와 같은 모양을 지닌다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
case WM_COMMAND:
    switch(LOWORD(wParam) {        // ID에 따른 분기
    case 메뉴1:처리1;break;
    case 메뉴2:처리2;break;
    case 액셀러레이터1:처리3;break;
    case 컨트롤1:
        switch(HIWORD(wParam)) {    // 통지 코드에 따른 분기
        case 통지코드1:처리4;break;
        case 통지코드2:처리5;break;
        ...........
        }
        break;
    }
return 0;
cs

 

 

 

 

 

 

 

 

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

7-3. 컨트롤 - 라디오 버튼  (0) 2021.12.27
7-2. 컨트롤 - 체크박스 버튼  (0) 2021.12.26
7. 컨트롤  (0) 2021.12.25
6. 그래픽 - 폰트  (0) 2021.12.25
6. 그래픽 - 비트맵  (0) 2021.05.05
Comments