교내 전공과목인 윈도우즈 API수업을 정리합니다
1. Mouse 버튼을 통해 선그리기를 해보자
(1) 소스코드
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
static int x;
static int y;
//static BOOL bNowDraw=FALSE;
switch (iMessage) {
case WM_LBUTTONDOWN:
/* 선그리기 시작을 알림 */
x = LOWORD(lParam);
y = HIWORD(lParam);
// bNowDraw=TRUE;
return 0;
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON) { // & = 비트연산자 // C언어에서 0 = False, 0이외의 수 = True
hdc = GetDC(hWnd);
MoveToEx(hdc, x, y, NULL);
x = LOWORD(lParam);
y = HIWORD(lParam);
LineTo(hdc, x, y);
ReleaseDC(hWnd, hdc);
}
return 0;
case WM_LBUTTONUP:
// bNowDraw=FALSE;
return 0;
case WM_LBUTTONDBLCLK:
InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
함수설명은 2번에서.
(2)실행화면
(3) 문제발생
창을 내렸다가 올리면 초기화가 되는 문제 발생
구조체를 이용하여 초기화 되지 않도록 만들어주자.
2. 창 초기화가 일어나지 않는 선그리기 프로그램 만들기
(0). 구현사항
1주차의 사각형 그리기에서도 구조체(has 점, 점 수)를 활용하여 방지해주었었다.
이와 같은 원리로 해결하자, 또한 백스페이스를 누르면 선 객체를 지울 수 있도록 만들자.
(1). 소스코드
typedef struct _line{
POINT p[1000];
int iPointCount;
} line; //선 객체 한 개의 표현
line lines[500];
int iLineCount; // 선 객체의 총 수
int iTempPointCount; // 한 개의 선 객체 내의 점개수 카운트
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps; //그려낼 화면
static int x;
static int y;
//static BOOL bNowDraw=FALSE;
switch (iMessage) {
case WM_KEYDOWN: // 선 객체 지우기
switch(wParam) {
case VK_BACK:
if (iLineCount > 0) {
iLineCount--;
InvalidateRect(hWnd, NULL, TRUE);
}
break;
}
return 0;
case WM_LBUTTONDOWN: // 선 그리기 시작
x = LOWORD(lParam);
y = HIWORD(lParam);
// bNowDraw=TRUE;
/* 구조체에 선 정보 (시작점) 저장하기 */
lines[iLineCount].p[iTempPointCount].x = x;
lines[iLineCount].p[iTempPointCount].y = y;
iTempPointCount++;
return 0;
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON) { // & = 비트연산자 // C언어에서 0 = False, 0이외의 수 = True
// MK_LBUTTON 0x0001 ->00000....0001
// MK_RBUTTON 0x0002 ->00000....0010
hdc = GetDC(hWnd);
MoveToEx(hdc, x, y, NULL);
x = LOWORD(lParam);
y = HIWORD(lParam);
LineTo(hdc, x, y);
ReleaseDC(hWnd, hdc);
/* 선 객체 정보 저장 (움직이는 점) */
ReleaseDC(hWnd, hdc);
lines[iLineCount].p[iTempPointCount].x = x;
lines[iLineCount].p[iTempPointCount].y = y;
iTempPointCount++;
}
return 0;
case WM_LBUTTONUP:
// bNowDraw=FALSE;
/* 선 객체의 정보 저장 ( 끝 점) */
lines[iLineCount].iPointCount = iTempPointCount;
iLineCount++; // 선 하나 증가
iTempPointCount = 0; // 초기화
return 0;
case WM_LBUTTONDBLCLK:
InvalidateRect(hWnd, NULL, TRUE);
return 0;
case WM_PAINT: // 저장된 선의 정보 그리기 실행
hdc = BeginPaint(hWnd, &ps);
for (int i = 0; i < iLineCount; i++){
for (int j = 0; j < lines[i].iPointCount - 1; j++){
MoveToEx(hdc, lines[i].p[j].x, lines[i].p[j].y, NULL);
LineTo(hdc, lines[i].p[j + 1].x, lines[i].p[j + 1].y);
}
}
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
- WM_LBUTTONDBLCLK : 마우스 더블왼쪽클릭했을 때
더블클릭으로 인정하는 클릭 간격은 시스템에 정의되어 있다. - GetDC( HWND hWnd);
- hWnd: 구하고자 하는 윈도우 핸들, NULL일 경우 전체 화면에 대한 DC가 구해짐
* WM_PAINT 메시지 내에서는 BeginPaint, EndPaint 함수쌍 이용
* WM_PAINT 메시지 외에서는 GetDC, ReleaseDC 함수쌍을 이용 - ReleaseDC(HWND hWnd, HDC hDC);
getDC로 구한 커먼 DC의 핸들은 반드시 이 함수로 해제해 주어야 한다.
- hWnd: 해제할 DC를 가진 윈도우의 핸들
- hDC: 해제할 DC핸들
(2). 실행화면
1과 달리 창의 변화가 와도 유지됨.
3. 메뉴바(선 색깔 변경) 를 만들어 보자.
(0) 구현사항
메뉴바를 통해 선색깔(빨/녹/파)을 선택할 수 있게 만들 것이다.
default색상을 빨강으로 설정할 것이다.
line구조체는 COLORREF penColor를 가질 것이고, 이를 통해 색상을 구현할 것이다.
(1)-1. 리소스 다루기
- 프로젝트 > 새 항목 추가 > 좌측 리소스(.rc)추가 > resoure.rc 탭 확인하기
- Resource.rc 우클릭 > menu 새로 만들기 > 항목 이름 설정하기
- 우측하단 메뉴 편집기 > ID패널 확인 (편한대로 바꾸기, RED, GREEN, BLUE)
- 솔루션 > 헤더파일 > resource.h에 ID를 다시 제대로 확인.
(1)-1. cpp 소스코드
#include "resource.h" // 리소스 적용하기 위한 헤더파일 적용
/* WinMain 함수에서 MenuID 적용하기 */
//WndClass.lpszMenuName = NULL;
WndClass.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1);
/* 구조체에 색상 속성 추가하기 */
typedef struct _line {
POINT p[1000];
int iPointCount;
COLORREF penColor; // 색상 속성
} line; //선 객체 한 개의 표현
/* WndProc에 사용할 전역변수 설정 */
line lines[500];
int iLineCount; // 선 객체의 총 수
COLORREF CurrentPenColor = RGB(255, 0, 0); // 현재 선 객체의 색상
// int iTempPointCount; // 한 개의 선 객체 내의 점개수 카운트
/* WndProc내의 지역변수 */
HDC hdc;
PAINTSTRUCT ps; //그려낼 화면
static int x;
static int y;
HPEN hPen; // 색상조절을 위한 펜 객체
//static BOOL bNowDraw=FALSE;
/* WndProc내의 Switch > WMCOMMAND */
case WM_COMMAND: //메뉴바 적용하기
switch (LOWORD(wParam)) {
case IDM_RED:
CurrentPenColor = RGB(255, 0, 0);
break;
case IDM_GREEN:
CurrentPenColor = RGB(0, 255, 0);
break;
case IDM_BLUE:
CurrentPenColor = RGB(0, 0, 255);
break;
}
return 0;
/* WndProc내의 Switch > WM_LBUTTONDOWN */
case WM_LBUTTONDOWN: // 선 그리기 시작
x = LOWORD(lParam);
y = HIWORD(lParam);
// bNowDraw=TRUE;
/* 구조체에 선 정보 (시작점) 저장하기 */
lines[iLineCount].p[lines[iLineCount].iPointCount].x = x;
lines[iLineCount].p[lines[iLineCount].iPointCount].y = y;
lines[iLineCount].iPointCount++;
lines[iLineCount].penColor = CurrentPenColor;
//lines[iLineCount].p[iTempPointCount].x = x;
//lines[iLineCount].p[iTempPointCount].y = y;
//iTempPointCount++;
return 0;
/* WndProc내의 Switch > WM_MOUSEMOVE */
case WM_MOUSEMOVE:
if (wParam & MK_LBUTTON) { // & = 비트연산자 // C언어에서 0 = False, 0이외의 수 = True
// MK_LBUTTON 0x0001 ->00000....0001
// MK_RBUTTON 0x0002 ->00000....0010
hdc = GetDC(hWnd);
/* 펜 설정 */
hPen = CreatePen(PS_SOLID, 1, lines[iLineCount].penColor);
SelectObject(hdc, hPen);
MoveToEx(hdc, x, y, NULL);
x = LOWORD(lParam);
y = HIWORD(lParam);
LineTo(hdc, x, y);
ReleaseDC(hWnd, hdc);
/* 선 객체 정보 저장 (움직이는 점) */
lines[iLineCount].p[lines[iLineCount].iPointCount].x = x;
lines[iLineCount].p[lines[iLineCount].iPointCount].y = y;
lines[iLineCount].iPointCount++;
//lines[iLineCount].p[iTempPointCount].x = x;
//lines[iLineCount].p[iTempPointCount].y = y;
//iTempPointCount++;
}
return 0;
/* WndProc내의 Switch > WM_LBUTTONUP */
case WM_LBUTTONUP:
// bNowDraw=FALSE;
/* 선 객체의 정보 저장 ( 끝 점) */
//lines[iLineCount].iPointCount = iTempPointCount;
iLineCount++; // 선 하나 증가
//iTempPointCount = 0; // 초기화
return 0;
/* WndProc내의 Switch > WM_PAINT */
case WM_PAINT: // 저장된 선의 정보 그리기 실행
hdc = BeginPaint(hWnd, &ps);
for (int i = 0; i < iLineCount; i++) {
hPen = CreatePen(PS_SOLID, 1, lines[i].penColor);
SelectObject(hdc, hPen);
MoveToEx(hdc, lines[i].p[0].x, lines[i].p[0].y, NULL);
for (int j = 1; j < lines[i].iPointCount; j++) {
LineTo(hdc, lines[i].p[j].x, lines[i].p[j].y);
}
}
EndPaint(hWnd, &ps);
return 0;
- SelectObject( HDC hdc,HGDIOBJ hgdiobj);
그리기에 사용할 GDI 오브젝트를 변경하고자 할 때 이 오브젝트를 만든 후 이 함수로 DC에 선택해 주어야 한다.
- hgdiobj: DC에 선택하고자 하는 GDI 오브젝트의 핸들, 이 obj는 CreatePen, CreateSolidBrush, CreateFont 등의 함수로 생성한 obj이거나 GetStrockObject로 구한 스톡 오브젝트여야 한다.
(2) 실행화면