1) 메시지 처리의 기본 개념
메시지를 처리한다 ↔ 프로그래밍 한다
<메시지의 종류>
1. 윈도우 메시지 : WM_로 시작(WM_COMMAND제외)
2. 컨트롤 통지 메시지 : Button, Combo Box와 같은 제어 객체나 자식 윈도우에서 부모 윈도우로 보내는 메시지
3. 명령 메시지 : WM_COMMAND
<메시지를 처리하기 위한 3단계>
1. 윈도우 클래스의 멤버 함수로 메시지 핸들러 함수를 선언한다.
2. 메시지 맵에 메시지와 메시지 핸들러 함수를 묶는 메시지의 매크로를 추가한다.
3. 메시지 핸들러 함수의 기능을 구현한다.
<메시지 핸들러 함수>
메시지 유형 |
발생 상황 |
메시지 핸들러 함수 |
WM_CREATE |
윈도우가 생성될 때 |
OnCreate() |
WM_ACTIVE |
윈도우가 활성화 될 때 |
OnActive() |
WM_PAINT |
윈도우가 다시 그려져야 될 때 |
OnPaint() |
WM_SIZE |
윈도우가 생성될 때 윈도우가 크기가 변경될 때 |
OnSize() |
WM_MOVE |
윈도우가 움직일 떄 |
OnMove() |
WM_TIMER |
설정된 타이머 시간이 됐을 떄 |
OnTimer() |
WM_DESTROY |
윈도우가 종료될 때 |
OnDestroy() |
2) 메시지 박스
int AfxMessageBox(LPCTSTR IpszText, UINT nType = MB_OK, UINT nIDHelp = 0);
- IpszText : 출력하고자 하는 문자열
- nType : 메시지 박스 출력 스타일
- nIDHelp : 현재 상태에서 F1키를 눌러 도움말을 실행하였을 때의 도움말 ID
메시지 박스 버튼 스타일 |
사용 가능한 버튼 |
AfxMessageBox 함수의 반환 값 |
MB_OK |
확인 |
IDOK |
MB_KOCANCEL |
확인 취소 |
IDOK, IDCANCEL |
MB_YESNO |
예 아니요 |
IDYES, IDNO |
MB_YESNOCANCEL |
예 아니요 취소 |
IDYES, IDNO, IDCANCEL |
MB_RETRYCANCEL |
다시시도 취소 |
IDRETRY, IDCANCEL |
MB_ABORTRETRYIGNORE |
중단 다시시도 무시 |
IDABORT, IDRETRY, IDIGNORE |
int CPractice3aView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 여기에 특수화된 작성 코드를 추가합니다.
//윈도우가 생성될 때 메시지 박스 출력
AfxMessageBox(_T("윈도우가 생성되었습니다."), MB_OKCANCEL | MB_ICONINFORMATION);
return 0;
}
void CPractice3aView::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//왼쪽 마우스를 더블 클릭할 때 메시지 박스 출력
AfxMessageBox(_T("왼쪽 마우스를 더블클릭했습니까?"), MB_YESNO | MB_ICONQUESTION);
CView::OnLButtonDblClk(nFlags, point);
}
void CPractice3aView::OnDestroy()
{
CView::OnDestroy();
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
//윈도우가 종료될 때 메시지 박스 출력
AfxMessageBox(_T("윈도우가 종료되었습니다."), MB_OK | MB_ICONWARNING);
}
3) 마우스 메시지
메시지 유형 |
발생 상황 |
메시지 핸들러 함수 |
WM_MOUSEMOVE |
마우스를 이동 |
OnMouseMove() |
WM_LBUTTONDBLCLK |
왼쪽 마우스 버튼을 더블 클릭 |
OnLButtonDblClk() |
WM_LBUTTONDOWN |
왼쪽 마우스 버튼을 누름 |
OnLButtonDown() |
WM_LBUTTONUP |
왼쪽 마우스 버튼을 놓음 |
OnLButtonUp() |
WM_RBUTTONDBLCLK |
오른쪽 마우스 버튼을 더블 클릭 |
OnRButtonDblClk() |
WM_RBUTTONDOWN |
오른쪽 마우스 버튼을 누름 |
OnRButtonDown() |
WM_RBUTTONUP |
오른쪽 마우스 버튼을 놓음 |
OnRButtonUp() |
WM_MOUSEWHEEL |
마우스 휠을 움직임 |
OnMouseWheel() |
<nFlags가 가질 수 있는 값>
- MK_CONTROL : ctrl 키가 눌림
- MK_LBUTTON : 왼쪽 마우스 버튼 눌림
- MK_MBUTTON : 가운데 마우스 버튼 눌림
- MK_RBUTTON : 오른쪽 마우스 버튼 눌림
- MK_SHIFT : shift 키가 눌림
CPractice3bView::CPractice3bView() noexcept
{
// TODO: 여기에 생성 코드를 추가합니다.
m_bTimerRun = false; //변수 초기화
m_bTimerType = true;
}
int CPractice3bView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 여기에 특수화된 작성 코드를 추가합니다.
SetTimer(0, 1000, NULL); //타이머 설정 //(타이머 ID, 메시지 발생시킬 간격, 메시지 발생시 실행되는 함수)
m_bTimerRun = TRUE; //타이머 동작
return 0;
}
void CPractice3bView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
int hour;
CString str;
CTime timer;
timer = CTime::GetCurrentTime();
if (m_bTimerType)
{
m_strTimer.Format(_T("현재는 %d년 %d월 %d일 %d시 %d분 %d초"),
timer.GetYear(), timer.GetMonth(), timer.GetDay(),
timer.GetHour(), timer.GetMinute(), timer.GetSecond());
}
else
{
hour = timer.GetHour();
if (hour >= 12)
{
str = _T("PM");
if (hour >= 13)
hour -= 12;
}
else
{
str = _T("AM");
}
m_strTimer.Format(_T("지금은 %s %d시 %d분 %d초"), str, hour,
timer.GetMinute(), timer.GetSecond());
}
Invalidate();
CView::OnTimer(nIDEvent);
}
void CPractice3bView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_bTimerType) //년, 월, 일, 시, 분, 초 형태로 출력 중
{
if (AfxMessageBox(_T("시, 분, 초 형태로 표시하겠습니까?"),
MB_YESNO | MB_ICONQUESTION) == IDYES)
{
m_bTimerType = false;
}
}
else //시, 분, 초 형태로 출력 중
{
if(AfxMessageBox(_T("년, 월, 일, 시, 분, 초형태로 표시하겠습니까?"),
MB_YESNO | MB_ICONQUESTION) == IDYES)
{
m_bTimerType = true;
}
}
CView::OnLButtonDown(nFlags, point);
}
void CPractice3bView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_bTimerRun == false)
{
if (AfxMessageBox(_T("디지털시계를 동작시키겠습니까?"),
MB_YESNO | MB_ICONQUESTION) == IDYES)
{
SetTimer(0, 1000, NULL); //타이머 설정
m_bTimerRun = true; //타이머 동작 => true
}
}
else //타이머가 동작 중일 때 메시지 박스 출력
{
if (AfxMessageBox(_T("정말로 디지털시계 동작을 멈추겠습니까?"),
MB_YESNO | MB_ICONQUESTION) == IDYES)
{
KillTimer(0); //타이머 해제
m_bTimerRun = false; //타이머 동작 => false
}
}
CView::OnRButtonDown(nFlags, point);
}
void CPractice3bView::OnDestroy()
{
CView::OnDestroy();
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
if (m_bTimerRun)
KillTimer(0); //타이머 해제
}
4) 키보드 메시지
메시지 유형 |
발생 상황 |
메시지 핸들러 함수 |
p147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
가상키 코드 |
대응되는 키보드 |
가상키 코드 |
대응되는 키보드 |
p148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CPractice3cView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
int nCharIndex;
nCharIndex = m_strOutput.GetLength(); //입력된 데이터의 길이를 얻는다.
if (nChar == VK_BACK) //백스페이스가 눌린경우
m_strOutput.Delete(nCharIndex - 1, 1); //한 번에 하나씩 지운다
else //백스페이스 이외의 키가 눌린 경우
m_strOutput += (WCHAR)nChar; //키보드로 입력된 문자를 문자열에 추가
Invalidate(); //화면갱신
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CPractice3cView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
switch (nChar) //가상키 코드 값에 대해
{
case VK_LEFT: //왼쪽 화살표 키를 누를 때
m_ptLocation.x--; //왼쪽으로 1픽셀 이동
break;
case VK_RIGHT: //오른쪽 화살표 키를 누를 때
m_ptLocation.x++; //오른쪽으로 1픽셀 이동
break;
case VK_UP: //위쪽 화살표 키를 누를 때
m_ptLocation.y--; //위쪽으로 1픽셀 이동
break;
case VK_DOWN: //아래쪽 화살표 키를 누를 때
m_ptLocation.y++; //아래쪽으로 1픽셀 이동
break;
case VK_PRIOR: //Pg UP 키를 누를 때
m_ptLocation.x--; //위쪽으로 1픽셀 이동
break;
case VK_NEXT: //Pg dn 키를 누를 때
m_ptLocation.x--; //아래쪽으로 1픽셀 이동
break;
case VK_HOME: //Home 키를 누를 때
m_ptLocation.x--; //처음 위치로 이동
break;
}
if (m_ptLocation.x < 0) //왼쪽 경계선을 만나면
{
m_ptLocation.x = 0; //m_ptLocation.x = 0으로 초기화
AfxMessageBox(_T("왼쪽으로 더 이상 이동할 수 없습니다."));
}
if (m_ptLocation.y < 0) //위쪽 경계선을 만나면
{
m_ptLocation.y = 0; //m_ptLocation.y = 0으로 초기화
AfxMessageBox(_T("위쪽으로 더 이상 이동할 수 없습니다."));
}
if (m_ptLocation.x > m_ptClientSize.x) //오른쪽 경계선을 만나면
{
m_ptLocation.x = m_ptClientSize.x; //m_ptLocation.x = 윈도우 x 크기로 초기화
AfxMessageBox(_T("오른쪽으로 더 이상 이동할 수 없습니다."));
}
if (m_ptLocation.y > m_ptClientSize.y) //아래쪽 경계선을 만나면
{
m_ptLocation.y = m_ptClientSize.y; //m_ptLocation.y = 윈도우 y 크기로 초기화
AfxMessageBox(_T("아래쪽으로 더 이상 이동할 수 없습니다."));
}
Invalidate(); //화면 갱신
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CPractice3cView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
m_ptClientSize.x = cx; //윈도우 영역의 가로(x) 길이를 얻음
m_ptClientSize.y = cy; //윈도우 영역의 세로(y) 길이를 얻음
Invalidate(); //화면 갱신
}
void CPractice3cView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (point.x >= m_ptLocation.x - 30 && point.x <= m_ptLocation.x + 30 && point.y > m_ptLocation.y - 30 && point.y <= m_ptLocation.y + 30)
{
m_bDrag = true;
}
m_ptLocation = point;
Invalidate();
CView::OnLButtonDown(nFlags, point);
}
void CPractice3cView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_bDrag)
{
m_ptLocation = point;
}
Invalidate();
CView::OnMouseMove(nFlags, point);
}
void CPractice3cView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_bDrag)
{
m_bDrag = false;
m_ptLocation = point;
}
Invalidate();
CView::OnLButtonUp(nFlags, point);
}
void CPractice3cView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_strOutput.IsEmpty() == false)
{
if (AfxMessageBox(_T("문자열을 모두 지우시겠습니까?"),
MB_YESNO | MB_ICONQUESTION) == IDYES)
{
m_strOutput.Empty();
}
}
else
{
AfxMessageBox(_T("문자열을 입력하시오."));
}
Invalidate();
CView::OnRButtonDown(nFlags, point);
}