컴퓨터/Win32-API
지금까지 배운 포스트들을 정리하면서 간단하게 RGB 개념을 적용해 3가지 인풋 박스에 R G B 순으로 숫자를 입력하고 색상을 표여주는 프로그램을 만들어 보도록 합시다.
전체 프로젝트 파일을 확인하고 싶으시면 Github을 참조해 주세요.
프로그램을 시작하는 WinMain 부분을 작성합니다.
프로그램의 메인이 윈도에 대한 설정과 메시지 루프 부분을 만들어 줍니다.
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"ColorTable";
wcex.hIconSm = NULL;
RegisterClassExW(&wcex);
//적용한 윈도우 생성 및 업데이트
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
HWND hWnd = CreateWindowW(L"ColorTable", L"ColorTable", 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;
}
R G B 각각의 값을 쓰고 읽기 위한 Edit 컨트롤을 만들어 줍니다.
HWND heditR, heditG, heditB; // 전역변수
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
switch (message)
{
case WM_CREATE:
heditR = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 40, 50, 25, hWnd, (HMENU)1, hInst, NULL);
heditG = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 70, 50, 25, hWnd, (HMENU)2, hInst, NULL);
heditB = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 100, 50, 25, hWnd, (HMENU)3, hInst, NULL);
break;
Edit컨트롤 박스의 효과적인 구분을 위해 WM_PAINT: 메시지에서 TextOut 함수를 통해 표시를 해 주었습니다.
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
//RGB 표시를 하기 위한 텍스트
TextOutW(hdc, 10, 45, L"R", 1);
TextOutW(hdc, 10, 75, L"G", 1);
TextOutW(hdc, 10, 105, L"B", 1);
EndPaint(hWnd, &ps);
}
break;
현재까지의 프로그램을 실행하면 다음과 같은 결과가 나오게 됩니다.
이제 Edit컨트롤으로 부터 사용자에게 입력받은 값을 처리해주는 작업을 해야 됩니다.
생각해 보면 요구사항은 다음과 같을 것입니다.
우선 입력되는 숫자를 제한하고 값을 받아오는 처리를 해보도록 합시다.
우선 Edit에서의 이벤트 동작은 WM_COMMAND 메시지에 wParam을 통해 들어옵니다. 메시지 처리를 위한 틀을 만들어 봅시다.
case WM_COMMAND:
switch (HIWORD(wParam))
{
//이벤트 메세지에 대한 구분
case EN_CHANGE:
//각각의 식별자에 대한 처리
if (LOWORD(wParam) == 1)
if (LOWORD(wParam) == 2)
if (LOWORD(wParam) == 3)
break;
}
break;
이후 0~255까지의 값만을 필요하기 때문에 이에 대한 처리를 해주도록 합시다.
우선 0~255 값을 받기 위한 전역 변수 int형 R, G, B와 임시적으로 Edit에서 문자열을 담기 위한 지역변수를 선언하도록 합시다.
int R, G, B; // 전역변수
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
WCHAR editword[10]; // 임시로 Edit에서 문자열값을 받기 위한 변수
//.....이하 소스코드
case WM_COMMAND:
switch (HIWORD(wParam))
{
case EN_CHANGE:
//R 처리
if (LOWORD(wParam) == 1) {
int num = 0;
if (GetWindowTextW(heditR, editword, GetWindowTextLengthW(heditR) + 1) != NULL) {
num = _wtoi(editword);
}
if (0 <= num && num <= 255) {
R = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
}
//.....이하 소스코드
위의 소스코드를 해석하면 아래와 같습니다.
_wtoi는 유니코드를 정수로 변환하기 위해 지원되는 함수입니다. c표준의 atoi와 동일한 개념
이후 정상적으로 적용된 값을 사용자에게 표시해주기 위해서 WM_PAINT를 호출하고 WM_PAINT 부분에 그리기를 처리해 줍시다.
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
//RGB 표시를 하기 위한 텍스트
TextOutW(hdc, 10, 45, L"R", 1);
TextOutW(hdc, 10, 75, L"G", 1);
TextOutW(hdc, 10, 105, L"B", 1);
//적용된 값 표시를 하기 위한 텍스트
wsprintf(editword, L"R : %d", R);
TextOutW(hdc, 100, 45, editword, lstrlenW(editword));
wsprintf(editword, L"G : %d", G);
TextOutW(hdc, 100, 75, editword, lstrlenW(editword));
wsprintf(editword, L"B : %d", B);
TextOutW(hdc, 100, 105, editword, lstrlenW(editword));
EndPaint(hWnd, &ps);
}
break;
이후 각각의 식별자에 대한 처리도 마무리해주도록 합시다.
switch (HIWORD(wParam))
{
case EN_CHANGE:
//R 처리
if (LOWORD(wParam) == 1) {
int num = 0;
if (GetWindowTextW(heditR, editword, GetWindowTextLengthW(heditR) + 1) != NULL) {
num = _wtoi(editword);
}
if (0 <= num && num <= 255) {
R = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
//G 처리
if (LOWORD(wParam) == 2) {
GetWindowTextW(heditG, editword, GetWindowTextLengthW(heditG) + 1);
int num = _wtoi(editword);
if (0 <= num && num <= 255) {
G = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
//B 처리
if (LOWORD(wParam) == 3) {
GetWindowTextW(heditB, editword, GetWindowTextLengthW(heditB) + 1);
int num = _wtoi(editword);
if (0 <= num && num <= 255) {
B = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
break;
}
이제 프로그램을 실행해 보면 다음과 같은 결과를 동작이 가능해집니다.
Edit 컨트롤을 이용해서 다양한 값을 받고 이동하여 저장하는 부분까지는 완료했습니다.
이제 이 값을 가지고 색을 칠하기만 하면 됩니다.
WM_PAINT에 하나의 사각형을 그리고 색을 칠해주기만 하면 됩니다.
//색 칠하기
HBRUSH newBrush = CreateSolidBrush(RGB(R, G, B));
HBRUSH OldBrush = (HBRUSH)SelectObject(hdc, newBrush);
Rectangle(hdc, 200, 50, 500, 400);
SelectObject(hdc,OldBrush);
DeleteObject(newBrush);
EndPaint(hWnd, &ps);
이제 프로그램을 구동해보면 RGB의 값을 입력받아 사각형의 색상을 변경할 수 있습니다.
향후 글에서는 이 프로그램을 가지고 다양한 기능을 추가해 보도록 하겠습니다.
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include "resource.h"
HINSTANCE hInst;
HWND heditR, heditG, heditB;
int R, G, B;
// 이 코드 모듈에 포함된 함수의 선언을 전달합니다:
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"ColorTable";
wcex.hIconSm = NULL;
RegisterClassExW(&wcex);
//적용한 윈도우 생성 및 업데이트
hInst = hInstance; // 인스턴스 핸들을 전역 변수에 저장합니다.
HWND hWnd = CreateWindowW(L"ColorTable", L"ColorTable", 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:
heditR = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 40, 50, 25, hWnd, (HMENU)1, hInst, NULL);
heditG = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 70, 50, 25, hWnd, (HMENU)2, hInst, NULL);
heditB = CreateWindowW(L"edit", NULL, WS_BORDER | WS_CHILD | WS_VISIBLE | ES_RIGHT | ES_NUMBER, 30, 100, 50, 25, hWnd, (HMENU)3, hInst, NULL);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
//RGB 표시를 하기 위한 텍스트
TextOutW(hdc, 10, 45, L"R", 1);
TextOutW(hdc, 10, 75, L"G", 1);
TextOutW(hdc, 10, 105, L"B", 1);
//적용된 값 표시를 하기 위한 텍스트
wsprintf(editword, L"R : %d", R);
TextOutW(hdc, 100, 45, editword, lstrlenW(editword));
wsprintf(editword, L"G : %d", G);
TextOutW(hdc, 100, 75, editword, lstrlenW(editword));
wsprintf(editword, L"B : %d", B);
TextOutW(hdc, 100, 105, editword, lstrlenW(editword));
//색 칠하기
HBRUSH newBrush = CreateSolidBrush(RGB(R, G, B));
HBRUSH OldBrush = (HBRUSH)SelectObject(hdc, newBrush);
Rectangle(hdc, 200, 50, 500, 400);
SelectObject(hdc,OldBrush);
DeleteObject(newBrush);
EndPaint(hWnd, &ps);
}
break;
case WM_COMMAND:
switch (HIWORD(wParam))
{
case EN_CHANGE:
//R 처리
if (LOWORD(wParam) == 1) {
int num = 0;
if (GetWindowTextW(heditR, editword, GetWindowTextLengthW(heditR) + 1) != NULL) {
num = _wtoi(editword);
}
if (0 <= num && num <= 255) {
R = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
//G 처리
if (LOWORD(wParam) == 2) {
GetWindowTextW(heditG, editword, GetWindowTextLengthW(heditG) + 1);
int num = _wtoi(editword);
if (0 <= num && num <= 255) {
G = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
//B 처리
if (LOWORD(wParam) == 3) {
GetWindowTextW(heditB, editword, GetWindowTextLengthW(heditB) + 1);
int num = _wtoi(editword);
if (0 <= num && num <= 255) {
B = num;
}
else {
MessageBox(hWnd, L"0 ~ 255의 숫자만 입력할 수 있습니다.", L"경고", NULL);
}
InvalidateRect(hWnd, NULL, TRUE);
}
break;
}
break;
case WM_SETTEXT:
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
결과물을 보니 중복된 함수도 많고 주석처리도 안되어 있어, 다음 글에서는 간단한 주석처리화 함수화를 해보겠습니다.
Win32_API - WM_PAINT 재호출(InvalidateRect,UpdateWindow) (0) | 2022.03.02 |
---|---|
Win32_API - 실습 - 마우스 좌표값 받아오기 (0) | 2022.03.01 |
Win32_API - Edit Control 값 사용하기 (inputbox) (0) | 2022.02.28 |
Win32_API - Edit Control (인풋박스,입력창) (0) | 2022.02.25 |
Win32_API - Pen & Brush (그리기 도구) (0) | 2022.02.24 |
91년생 공학엔지니어의 개발일지
TODAY :
YESTER DAY :
TOTAL :
Commnet