Win32_API - Edit Control 값 사용하기 (inputbox)

컴퓨터/Win32-API

728x90
반응형

서론

본문에서는 Edit 컨트롤의 값을 받아서 사용하는 방법에 대하여 알아보도록 하겠습니다.

리소스 형태를 사용하지 않고 사용하는 방법에 대하여 서술하겠습니다.

컨트롤 또한 하나의 윈도라는 개념을 이해하고 확장하여 만들어 보도록 합시다.

 

1. 전역 변수 HWND 만들기

우선 컨트롤 또한 하나의 Window이기 때문에 전체적으로 Windwos를 제어할 수 있도록 전역 변수를 만들어 보도록 합시다.

 

HWND hedit;

 

 

2. WM_CREATE: CreateWindow - Edit 컨트롤 만들기

컨트롤을 만들기 위해 상위 윈도가 만들어질 때 발생되는 WM_CREATE 메시지에서 CreateWindow 함수를 통해 Edit을 만들어 줍니다.

이때 미리 선언해 둔 전역 변수 hedit에 값을 담아줍니다.

    case WM_CREATE:
        hedit = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_NUMBER | ES_RIGHT, 20, 20, 100, 25, hWnd, NULL, hInst, NULL);
        break;

 

3.Edit 컨트롤에서 값을 받기 - GetWindowText 함수

특정 윈도에서 텍스트 값을 받을 수 있는 함수가 GetWindow함수입니다.

우선 함수의 원형을 살펴보면 다음과 같습니다.

int GetWindowTextW(
    _In_ HWND hWnd,
    _Out_writes_(nMaxCount) LPWSTR lpString,
    _In_ int nMaxCount);
  • 윈도우 핸들
  • 문자를 받을 LPWString
  • 문자의 개수(크기)
  • 이 함수는 받아온 문자의 크기를 반환해 줍니다. 만약 에러가 발생하거나 값이 없다면 0을 반환합니다.

 

위 함수를 사용하려면 일단 문자를 받을 공간이 필요합니다. 따라서 문자를 받을 공간을 정의해주고,

함수를 통해 값을 받아줍니다.

 

WCHAR editword[10];
GetWindowTextW(hedit, num_char, GetWindowTextLengthW(hedit)+1)

여기서 문자열의 길이는 마지막 null문자를 포함하기 위해 +1을 해줍니다.

4. 받아온 값을 출력해 봅시다.

받아온 값을 출력하기 위해서는 Edit에 값이 수정될 때마다 출력을 하기 위한 처리가 필요합니다.

본문에서는 지난 글에서 작성한 내용처럼 EN_CHANGE를 통해 처리를 해보도록 합시다.

WM_COMMAND라는 메인 메시지의 wParam의 HIWORD를 통해 전달받습니다.

    case WM_COMMAND:

        switch (HIWORD(wParam))
        {
        case EN_CHANGE:
        	// 값 받아오기 
            hdc = GetDC(hWnd);
			// 잘 받아왔다면 값 출력하기

            ReleaseDC(hWnd, hdc);
            break;
        }
        break;

위의 메시지 틀에 위의 내용을 추가하면 아래와 같은 내용이 될 것입니다.

 

    WCHAR editword[100];
        case WM_COMMAND:
            switch (HIWORD(wParam))
            {
            case EN_CHANGE:
                hdc = GetDC(hWnd);
                if(GetWindowTextW(hedit, editword, GetWindowTextLengthW(hedit)+1) != NULL){
                TextOutW(hdc, 100, 100, editword, lstrlenW(editword));
                }
                else{
                TextOutW(hdc, 100, 100, L" ", 1);
                }
                ReleaseDC(hWnd, hdc);
                break;
            }
        break;

여기서 if문을 과 GetWindowText의 반환 값을 활용하여 Edit 컨트롤에 값이 들어왔을 때만 출력하기를 처리해 줍니다.

5.WM_PAINT 처리하기

WM_PAINT에서 아무것도 그리지 않는다면 PAINT 메시지 발생 시 출력했던 값이 사라지는 문제가 생깁니다.

따라서 동일하게 처리해 줍니다.

    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd, &ps);
            if (GetWindowTextW(hedit, editword, GetWindowTextLengthW(hedit) + 1) != NULL) {
                TextOutW(hdc, 100, 100, editword, lstrlenW(editword));
            }
            else {
                TextOutW(hdc, 100, 100, L" ", 1);
            }
            EndPaint(hWnd, &ps);
        }
        break;

 

 

6. 약간의 문제가 발생한다. - InvalidateRect함수의 필요성

여기까지 완성하고 프로그램을 동작시키면 약간의 문제가 발생하게 됩니다. 

이미 Edit컨트롤에서 받은 값을 통해서 출력을 한 이후에 Edit 컨트롤에 값을 지우게 되더라도 공백 한 칸 만을 출력하기 때문에 이미 길게 출력된 값들이 남아 있습니다. 

이 값들을 초기화하기 위한 방법이 필요합니다. 

여기서 가장 간단한 방법으로 InvalidateRect함수를 사용하면 됩니다.

간단하게 설명하자면 이 함수는 그리기 값을 초기화하고 다시 그리기 위한 함수입니다.

이 함수에 대해서는 다른 포스트에서 다시 자세히 설명하도록 하겠습니다.

 

다시 본론으로 돌아가서, 이 함수를 사용하여 문제점을 극복할 수 있습니다.

    case WM_COMMAND:

        switch (HIWORD(wParam))
        {
        case EN_CHANGE:
            hdc = GetDC(hWnd);

            InvalidateRect(hWnd, NULL, TRUE);
            if (GetWindowTextW(hedit, editword, GetWindowTextLengthW(hedit)+1) != NULL) {
                TextOutW(hdc, 100, 100, editword, lstrlenW(editword));
            }

            ReleaseDC(hWnd, hdc);
            break;
        }
        break;

 

7. 전체 소스코드

이제 전체 소스코드를 확인하고 원하는 동작이 이루어졌는지 확인해 봅시다.


#include <windows.h>

#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <Shlwapi.h>
#include "resource.h"


HINSTANCE hInst;
HWND hedit;
int num;

// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
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 = MAKEINTRESOURCE(IDR_MENU1);
    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;
    WCHAR editword[10];
    switch (message)
    {
    case WM_CREATE:
        hedit = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT, 20, 20, 100, 25, hWnd, NULL, hInst, NULL);
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            hdc = BeginPaint(hWnd, &ps);
            if (GetWindowTextW(hedit, editword, GetWindowTextLengthW(hedit) + 1) != NULL) {
                TextOutW(hdc, 100, 100, editword, lstrlenW(editword));
            }

            EndPaint(hWnd, &ps);
        }
        break;
    case WM_COMMAND:

        switch (HIWORD(wParam))
        {
        case EN_CHANGE:
            hdc = GetDC(hWnd);

            InvalidateRect(hWnd, NULL, TRUE);
            if (GetWindowTextW(hedit, editword, GetWindowTextLengthW(hedit)+1) != NULL) {
                TextOutW(hdc, 100, 100, editword, lstrlenW(editword));
            }

            ReleaseDC(hWnd, hdc);
            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 :