WindowsAPI - DialogBox 만들고 사용해보기 (대화 상자 사용해 보기)

컴퓨터/Win32-API

728x90
반응형

서론

지난번 포스트에서 간단하게 DialogBox에 대한 개념을 알아보았습니다.

크게 2가지의 종류로 구분할 수 있다고 했습니다. 

  • 사용자 정의 템플릿을 사용한 대화 상자
  • WindowsAPI에서 제공하는 공용 템플릿을 사용한 대화 상자

본문에서는 사용자 정의 템플릿을 사용한 대화 상자를 이해하고 구현해 보도록 합시다.

 

템플릿과 처리를 위한 프로시저

개발자가 WindowsAPI에서 대화 상자의 기능을 동작시키고 이용하려면 다음과 같은 과정이 필요합니다.

  • 정의된 DialogBox의 틀을 불러오거나 새롭게 DialogBox에 사용할 틀을 만든다.
    • 즉, 대화상자의 형태를 담당할 템플릿이 필요합니다.
  • 이후 원하는 시점에 템플릿을 이용해서 DialogBox를 만든다.
    • 특정 동작을 할 때 DialogBox가 생성이 돼야 됩니다. 예를 들어 파일 열기와 같이 말이죠.
  • 생성된 Dialogbox에서 사용자로부터 입력받은 정보를 처리하는 과정이 필요하다.
    • 생성된 Dialogbox에서 무언가 입력 또는 동작 등이 이루어지면 이를 처리하는 과정이 필요합니다(프로시저)

 

위의 3가지 과정을 간단하게 정리하자면 다음과 같습니다.

  • 템플릿이 존재해야 한다.
  • 필요한 시점에 템플릿을 이용해 대화 상자를 만든다.
  • 대화 상자에서 동작하는 내용을 처리한다.

이 과정들을 하나씩 구현해보도록 하겠습니다.

 

템플릿 만들기

앞서 언급했다시피, 템플릿 즉 대화 상자를 찍어내기 위한 하나의 틀을 말합니다. 

본문에서는 리소스를 이용해서 간단하게 이 템플릿을 만들어 보도록 합시다.

 

  • 리소스 생성

Visualstudio를 통해 Dialog리소스를 생성해 주도록 합시다.

생성된 Dialog 템플릿

  • 템플릿을 알맞게 수정하기

Visualstudio에서 제공하는 대화 상자 편집기를 통해 다양한 형태로 템플릿을 간단하게 수정할 수 있습니다.

  • 자동 생성된 resource.h 확인해보기

위처럼 편집기를 통해 리소스를 등록하면 visualstudio에서 사용하기 쉽게 항목들을 데이터화 시켜줍니다.

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++에서 생성한 포함 파일입니다.
// Mywin32.rc에서 사용되고 있습니다.
//
#define IDI_ICON1                       101
#define IDI_ICON2                       102

//실습을 위해 생성된 대화상자에 들어있는 리소스
#define IDD_DIALOG1                     118
#define IDC_CHECK1                      1001
#define IDC_CHECK2                      1002
#define IDC_CHECK3                      1003

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        120
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1003
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

원하는 시점에 템플릿을 이용해 DialogBox 만들기 -DialogBox()

이제 만들어진 템플릿을 이용해서 원하는 시점에 대화상자를 만들어 보도록 합시다.

우선 대화상자를 생성하기 위한 가장 기본적인 함수 DialogBox()의 선언부를 살펴보면 다음과 같습니다.

void DialogBox(
  [in, optional]  hInstance,
  [in]            lpTemplate,
  [in, optional]  hWndParent,
  [in, optional]  lpDialogFunc
);
  • hInstance - 템플릿이 들어있는 모듈에 대한 핸들 값, NULL시 실행되고 있는 파일이 사용됩니다.
  • IpTemplat - 사용할 템플릿의 포인터 값 MAKEINTERSOURCE를 통해 리소스에 접근할 수 있습니다.
  • hWndParent - 부모 윈도의 핸들 값
  • IpDialogFunc - 해당 대화 상자를 처리할 함수의 이름(콜백함수) 

이를 이용하여 WM_CREATE에서 대화상자를 생성해 보도록 합시다.

    case WM_CREATE:
    {
        DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1), hWnd, NULL);
        break;
    }

WM_CREATE 메시지를 처리하는 과정에서 대화 상자가 생성되어 표시되었습니다. 

하지만, 처리하는 프로시저에 대한 내용이 없기 때문에 정상적인 동작을 하지 않는 것을 확인할 수 있습니다.

 

프로시저를 만들고 대화 상자의 내용 처리하기

이제 생성된 대화상자의 내용을 처리하는 과정을 만들어 주어야 합니다.

콜백 함수의 형태로 개발자가 직접 정의하여 처리를 할수있도록 도와줍니다.

콜백함수의 형태는 다음과 같습니다.

BOOL CALLBACK DeleteItemProc(HWND hwndDlg, 
                             UINT message, 
                             WPARAM wParam, 
                             LPARAM lParam)

위의 원형을 보고 제가 사용하기 위한 함수를 소스코드에서 정의해주고 생성되는 시점에서 연동시켜 주도록 합시다.

//대화 상자용 콜백함수
BOOL CALLBACK MyDialogBox(HWND hwndDig, UINT message, WPARAM wParam, LPARAM IParam) {

}



LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        //대화 상자 적용 및 콜백함수 연동하기
        DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1), hWnd,(DLGPROC)MyDialogBox);
        break;
    }
    case WM_COMMAND:
    {

        break;
    }
    case WM_PAINT:
    {

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

WndProc와 비슷한 구조입니다. 즉, 대화 상자에서 발생하는 처리 또한 콜백 함수에서 메시지와 파라미터의 형태로 처리가 가능하다는 말입니다.

 

그럼 간단하게 동작을 제어하기 위한 몇 가지 소스코드를 작성해 보도록 합시다.

(다양한 동작이나 메시지는 MSDN에서 찾아보도록 합시다!)

//대화 상자용 콜백함수
BOOL CALLBACK MyDialogBox(HWND hwndDig, UINT message, WPARAM wParam, LPARAM IParam) {

    static WCHAR word[20] = L"push button";
    static int number;
    switch (message)
    {
    case WM_INITDIALOG:
    {

    }
    case WM_COMMAND:
    {
        switch (wParam)
        {
        case IDC_CHECK1:
                number = 1;
                wsprintfW(word, L"last check box : %d", number);
                break;

        case IDC_CHECK2:
                number = 2;
                wsprintfW(word, L"last check box : %d", number);
                break;
        case IDC_CHECK3:
                number = 3;
                wsprintfW(word, L"last check box : %d", number);
                break;
        case IDOK:
        case IDCANCEL:
            EndDialog(hwndDig, 0);
            return TRUE;
        }
        InvalidateRect(hwndDig, NULL, TRUE);
        UpdateWindow(hwndDig);
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwndDig, &ps);
        TextOutW(hdc, 10, 10, word, lstrlen(word));
        EndPaint(hwndDig, &ps);
    }
    }
    return FALSE;
}

해당 코드를 실행시켜보면 생성한 대화 상자에서 체크박스의 동작에 따라 텍스트가 변경되는 것을 확인할 수 있습니다.

 

MSDN을 보고 다양한 방법으로 응용해 보세요.

 

전체 소스코드

// Windows 헤더 파일
#include <windows.h>
// C 런타임 헤더 파일입니다.
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <wincodec.h>
#include "resource.h"
// 전역 변수:
HINSTANCE hInst;                                // 현재 인스턴스입니다.
HWND hButton;
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK MyDialogBox(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;
}

//대화 상자용 콜백함수
BOOL CALLBACK MyDialogBox(HWND hwndDig, UINT message, WPARAM wParam, LPARAM IParam) {

    static WCHAR word[20] = L"push button";
    static int number;
    switch (message)
    {
    case WM_INITDIALOG:
    {

    }
    case WM_COMMAND:
    {
        switch (wParam)
        {
        case IDC_CHECK1:
                number = 1;
                wsprintfW(word, L"last check box : %d", number);
                break;

        case IDC_CHECK2:
                number = 2;
                wsprintfW(word, L"last check box : %d", number);
                break;
        case IDC_CHECK3:
                number = 3;
                wsprintfW(word, L"last check box : %d", number);
                break;
        case IDOK:
        case IDCANCEL:
            EndDialog(hwndDig, 0);
            return TRUE;
        }
        InvalidateRect(hwndDig, NULL, TRUE);
        UpdateWindow(hwndDig);
    }
    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwndDig, &ps);
        TextOutW(hdc, 10, 10, word, lstrlen(word));
        EndPaint(hwndDig, &ps);
    }
    }
    return FALSE;
}



LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_CREATE:
    {
        //대화 상자 적용 및 콜백함수 연동하기
        DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG1), hWnd,(DLGPROC)MyDialogBox);
        break;
    }
    case WM_COMMAND:
    {

        break;
    }
    case WM_PAINT:
    {

    }
    break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
728x90
반응형

Commnet

G91개발일지

Gon91(지구일)

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

TODAY :

YESTER DAY :

TOTAL :