Win32_API - 여러개의 버튼 처리

컴퓨터/Win32-API

728x90
반응형

서론

지난 포스트를 보면 단순하게 하나의 버튼을 만들고 WM_COMMAND 메시지와 함께 wParam으로 BN_CLICKED라는 인자가 들어오면 동작을 하게 하였습니다. 

만약 2개 이상의 버튼이 생기고 각각의 버튼을 눌렀을때의 처리를 다르게 하고 싶다면, 해당 방법으로는 문제점이 발생하게 됩니다. 어떤 버튼을 클릭했는지에 대한 처리가 되어있지 않기 때문입니다.

본문에서는 이런 내용들을 해결하기 위한 방법을 공부해 보도록 하겠습니다.

 

생성하는 과정에서 식별자 부여하기

우선 CreateWindow 함수를 통해 생성하는 과정에서 식별자의 부여가 필요합니다. 

다시 말하자면 이 버튼의 ID값은 몇이다 라고 부여해주어야 한다는 말입니다.

이 인자는 9번째 인자인 HMENU를 통해 부여하게 됩니다. 예를 들어 2개의 버튼을 만든다고 가정하면 아래와 같이 각각의 아이디를 부여하도록 합시다. 

CreateWindowW(L"button",L"buttion1", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 20, 100, 25,hWnd, (HMENU)100 , hInst,NULL);
CreateWindowW(L"button", L"buttion2", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 60, 100, 25, hWnd, (HMENU)101, hInst, NULL);

여기서 인자의 형태가 HMENU기 때문에 HMENU의 형태로 형변환이 필요합니다.

 

어떻게 구분하여 명령을 처리하는가?

이제 각각의 버튼에 식별자 부여를 완료했으면 정확한 버튼에 따른 처리가 필요합니다. 

MSDN 통해 검색하면 다음과 같은 자료를 찾을 수 있습니다.

 

 

단추 메시지 - Win32 apps

단추는 부모 창에 메시지를 보낼 수 있으며, 부모 창은 단추로 메시지를 보낼 수 있습니다.

docs.microsoft.com

필요한 내용을 정리하자면 다음과 같습니다.

  • 단추를 클릭하면 WM_COMMAND 메시지가 부모 창으로 보냅니다.
  • wParam을 통해 낮은 순서에는 식별자가 포함됩니다.
  • wParam을 통해 높은 순서에 알림 코드가 포함됩니다.

LOWORD와 HIWORD를 이용하여 wParam을 분할할 수 있으니, 해당 내용을 모두 적용시켜 소스코드를 작성해 봅시다.

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case 100:
            if(HIWORD(wParam) == BN_CLICKED){
            MessageBox(hWnd, L"button1 클릭 되었습니다!",L"buttion1",NULL);
            }
            break;
        case 101:
            if (HIWORD(wParam) == BN_CLICKED) {
            MessageBox(hWnd, L"button2 클릭 되었습니다!", L"buttion2", NULL);
            }
            break;
        }
        break;

 

전체 소스코드

이제 전체 소스코드를 활용해서 직접 테스트해보세요


#include <windows.h>

#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>


HINSTANCE hInst;

// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{

    //윈도우 창 구조체 정의 및 적용
    WNDCLASSEXW wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = NULL;
    wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;
    wcex.lpszClassName = L"Test";
    wcex.hIconSm = NULL;
    RegisterClassExW(&wcex);

    //적용한 윈도우 생성 및 업데이트
    hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
    HWND hWnd = CreateWindowW(L"Test", L"Test", WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    if (!hWnd)
    {
        return FALSE;
    }
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    MSG msg;

    // 기본 메시지 루프입니다:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    switch (message)
    {
    case WM_CREATE:
        CreateWindowW(L"button",L"buttion1", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 20, 100, 25,hWnd, (HMENU)100 , hInst,NULL);
        CreateWindowW(L"button", L"buttion2", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 20, 60, 100, 25, hWnd, (HMENU)101, hInst, NULL);

        break;
    case WM_LBUTTONDOWN:
        hdc = GetDC(hWnd); //DC을얻는 방법 1
        ReleaseDC(hWnd, hdc);
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: 여기에 hdc를 사용하는 그리기 코드를 추가합니다...
            TextOutW(hdc, 100, 100, L"Hello World", 12);
            TextOutA(hdc, 200, 200, "Hello World", 12);
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case 100:
            if(HIWORD(wParam) == BN_CLICKED){
            MessageBox(hWnd, L"button1 클릭 되었습니다!",L"buttion1",NULL);
            }
            break;
        case 101:
            if (HIWORD(wParam) == BN_CLICKED) {
            MessageBox(hWnd, L"button2 클릭 되었습니다!", L"buttion2", NULL);
            }
            break;
        }
        break;
    case WM_SETTEXT:

    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

 

마무리

본문을 통해 버튼에 식별자를 부여하고 각각의 버튼에 처리를 하는 과정을 배웠습니다.

식별자의 중복을 방지하기 위한 방법이나 쉽게 사용하는 방법이 필요합니다.

728x90
반응형

Commnet

G91개발일지

Gon91(지구일)

91년생 공학엔지니어의 개발일지

TODAY :

YESTER DAY :

TOTAL :