결혼 전에는 공작, 약혼을 하면 사자, 결혼을 하면 당나귀. -스페인속담
2.1 pbm.hpp #
#ifndef __PENBRUSHMANAGER_HPP__
#define __PENBRUSHMANAGER_HPP__
#include <windows.h>
#define PEN_BRUSH_MAX_NUM 3
struct PenBrushManager {
HPEN pen[PEN_BRUSH_MAX_NUM], oldpen;
HBRUSH brush[PEN_BRUSH_MAX_NUM], oldbrush;
void init();
void fini();
void BeginPen(HDC hdc, int idx);
void EndPen(HDC hdc);
void BeginBrush(HDC hdc, int idx);
void EndBrush(HDC hdc);
};
#endif
2.2 pbm.cpp #
#include "pbm.hpp"
void PenBrushManager::init() {
this->pen[0] = CreatePen(PS_SOLID, 2, RGB(255, 0, 0));
this->pen[1] = CreatePen(PS_SOLID, 2, RGB(0, 255, 0));
this->pen[2] = CreatePen(PS_SOLID, 2, RGB(0, 0, 255));
this->brush[0] = CreateSolidBrush(RGB(255, 0, 0));
this->brush[1] = CreateSolidBrush(RGB(0, 255, 0));
this->brush[2] = CreateSolidBrush(RGB(0, 0, 255));
}
void PenBrushManager::fini() {
for (int i = 0; i < PEN_BRUSH_MAX_NUM; i++) {
DeleteObject(this->pen[i]);
DeleteObject(this->brush[i]);
}
}
void PenBrushManager::BeginPen(HDC hdc, int idx) {
oldpen = (HPEN) SelectObject(hdc, this->pen[idx]);
}
void PenBrushManager::EndPen(HDC hdc) {
SelectObject(hdc, oldpen);
}
void PenBrushManager::BeginBrush(HDC hdc, int idx) {
oldbrush = (HBRUSH) SelectObject(hdc, this->brush[idx]);
}
void PenBrushManager::EndBrush(HDC hdc) {
SelectObject(hdc, oldbrush);
}
2.3 main.cpp에서 윈도우 프로시져 부분만 #
당연하겠지만 #include "pbm.hpp"을 추가해야 컴파일되겠죠? (의외로 간단한 것때문에 해메시는 분들이 많습니다)
/* 이 함수는 윈도우즈 함수 DispatchMessage()를 호출할 때 실행됩니다. */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static PenBrushManager pbm_;
static RECT rc_[3];
static int curr_pen;
static POINT points[512];
static bool movemodes[512];
static int point_num = 0;
static bool prev_movemodes = 0; // 0 : MoveToEx(), 1 : LineTo()
switch (message) /* 메세지에 따라 분기합니다 */
{
case WM_CREATE:
SetRect(&rc_[0], 10, 10, 20, 20);
SetRect(&rc_[1], 30, 10, 40, 20);
SetRect(&rc_[2], 50, 10, 60, 20);
curr_pen = 0;
pbm_.init();
break;
case WM_LBUTTONDOWN:
{
const POINT p = {LOWORD(lParam), HIWORD(lParam)};
if (PtInRect(&(rc_[0]), p)) curr_pen = 0;
if (PtInRect(&(rc_[1]), p)) curr_pen = 1;
if (PtInRect(&(rc_[2]), p)) curr_pen = 2;
}
break;
case WM_RBUTTONDOWN:
point_num = 0; // 모든 그림기록을 지운다.
break;
case WM_MOUSEMOVE:
// 만일 point_num가 한계를 넘어가면 그냥 break한다.
if ( point_num == 512 ) break;
// 좌표를 배열에 대입한다.
points[point_num].x = LOWORD(lParam);
points[point_num].y = HIWORD(lParam);
movemodes[point_num] = prev_movemodes;
// 왼쪽 버튼을 누르고 있는 동안만 배열에 추가한다. 이렇게 하면 배열안에 공간이 절약된다.
if ( (wParam & MK_LBUTTON) ) point_num++;
// 왼쪽 버튼이 눌려있는 여부로 현재 그릴것인지 여부를 결정한다.
prev_movemodes = (bool)(wParam & MK_LBUTTON);
InvalidateRect( hwnd, NULL, TRUE);
break;
case WM_PAINT :
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
// 네모칸을 그린다. 이 부분을 선택하면 색상이 변하게 된다.
for (int i = 0; i < 3; i++) {
pbm_.BeginBrush(hdc, i);
Rectangle(hdc, rc_[i].left, rc_[i].top, rc_[i].right, rc_[i].bottom);
pbm_.EndBrush(hdc);
}
// 선을 그린다.
pbm_.BeginPen(hdc, curr_pen);
MoveToEx(hdc, points[0].x, points[0].y, NULL);
for (int i = 0; i < point_num; i++) {
if (movemodes[i])
LineTo(hdc, points[i].x, points[i].y);
else
MoveToEx(hdc, points[i].x, points[i].y, NULL);
}
pbm_.EndPen(hdc);
{
char buf[512];
sprintf(buf, "%d개 저장중", point_num);
TextOut(hdc, 10, 30, buf, strlen(buf));
}
if ( point_num == 512 ) TextOut(hdc, 10, 10, "오버플로우!", 11);
EndPaint( hwnd, &ps );
}
break;
case WM_DESTROY:
pbm_.fini();
PostQuitMessage (0); /* 메세지 큐에 WM_QUIT 메세지를 보냅니다. */
break;
default: /* 다루지 않은 메세지는 모두 운영체계에게 넘깁니다. */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}









![[http]](/wiki/imgs/http.png)
