윈도우 프로그래밍 Visual C++ 2010 MFC Programming(김선우, 신화서 저) 5장 연습문제입니다.
우선 1~8번 문제까지 풀어봤습니다.
[5-1]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
BOOL m_bDrawMode; //그리기 작업이 진행 중
int m_x1, m_y1, m_x2, m_y2; //타원에 외접하는 직사각형의 좌상단/우하단 좌표
CList<CRect, RECT> list;
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
// afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
};
// ChildView.cpp: CChildView 클래스의 구현
//윈도우가 다른 윈도우에 가려지거나 최소화 상태에서 복원되어 다시 그려져도,
//그렸던 타원이 모두 나타나도록 DrawCircles 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-1.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
m_bDrawMode = FALSE;
}
CChildView::~CChildView()
{
list.RemoveAll();
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
POSITION pos = list.GetHeadPosition();
while (pos != NULL)
{
CRect rect = list.GetNext(pos);
dc.Ellipse(&rect);
}
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드 시작
m_bDrawMode = TRUE;
//좌표 저장
m_x1 = m_x2 = point.x;
m_y1 = m_y2 = point.y;
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드면 타원을 지우고 그리기 반복
if (m_bDrawMode)
{
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//이전에 그린 타원을 지운다
dc.SetROP2(R2_NOT);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
CWnd::OnMouseMove(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//최종적인 타원을 그린다
dc.SetROP2(R2_COPYPEN);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
CRect rect(m_x1, m_y1, m_x2, m_y2);
list.AddTail(rect);
//그리기 모드 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
[5-2]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
BOOL m_bDrawMode; //그리기 작업이 진행 중임을 나타낸다
int m_x1, m_y1, m_x2, m_y2; //타원에 외접하는 직사각형의 좌상단/우하단 좌표
COLORREF color;
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};
// ChildView.cpp: CChildView 클래스의 구현
//R 키를 누르면 빨간색, G 키를 누르면 초록색, B 키를 누르면 파란색 원을 그리도록
//DrawCircles 예제를 수정하시오.
#include "stdafx.h"
#include "연습문제 5-2.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
m_bDrawMode = FALSE;
color = RGB(255, 0, 0); //default color
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
m_bDrawMode = TRUE;
//좌표를 저장한다
m_x1 = m_x2 = point.x;
m_y1 = m_y2 = point.y;
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
CClientDC dc(this);
CPen pen(PS_SOLID, 2, color);
dc.SelectObject(&pen);
dc.SelectStockObject(NULL_BRUSH);
//최종적인 타원을 그린다
dc.SetROP2(R2_COPYPEN);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//그리기 모드 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드면 타원을 지우고 그리기를 반복한다
if (m_bDrawMode)
{
CClientDC dc(this);
CPen pen(PS_SOLID, 2, color);
dc.SelectObject(&pen);
dc.SelectStockObject(NULL_BRUSH);
//이전에 그린 타원을 지운다
dc.SetROP2(R2_NOT);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
CWnd::OnMouseMove(nFlags, point);
}
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//아스키 코드 참고
switch (nChar)
{
case 82:
case 114:
color = RGB(255, 0, 0);
break;
case 71:
case 103:
color = RGB(0, 255, 0);
break;
case 66:
case 98:
color = RGB(0, 0, 255);
break;
}
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
[5-3]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
BOOL m_bDrawMode; //그리기 작업이 진행 중임을 나타낸다
int m_x1, m_y1, m_x2, m_y2; //타원에 외접하는 직사각형의 좌상단/우하단 좌표
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
};
// ChildView.cpp: CChildView 클래스의 구현
//Shift 키를 누르면 직사각형을 그리도록 DrawCircles 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-3.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
m_bDrawMode = FALSE;
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드 시작
m_bDrawMode = TRUE;
//좌표 저장
m_x1 = m_x2 = point.x;
m_y1 = m_y2 = point.y;
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//최종적인 타원 그림
dc.SetROP2(R2_COPYPEN);
m_x2 = point.x;
m_y2 = point.y;
if (GetKeyState(VK_SHIFT)) //shift 눌렀을 경우
dc.Rectangle(m_x1, m_y1, m_x2, m_y2);
else //풀었을 경우
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//그리기 모드 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드면 타원을 지우고 그리기 반복
if (m_bDrawMode)
{
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//이전에 그린 타원을 지운다
if (GetKeyState(VK_SHIFT)) //shift 누른 상태
{
dc.SetROP2(R2_NOT);
dc.Rectangle(m_x1, m_y1, m_x2, m_y2);
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
m_x2 = point.x;
m_y2 = point.y;
dc.Rectangle(m_x1, m_y1, m_x2, m_y2);
}
else //shift 다시 눌러 풀은 상태
{
dc.SetROP2(R2_NOT);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
}
CWnd::OnMouseMove(nFlags, point);
}
[5-4]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
BOOL m_bDrawMode; //그리기 작업이 진행 중임을 나타낸다
int m_x1, m_y1, m_x2, m_y2; //타원에 외접하는 직사각형의 좌상단/우하단 좌표
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
};
// ChildView.cpp: CChildView 클래스의 구현
//Ctrl 키를 누르면 빨간색으로 채워진 타원을 그리도록 DrawCircles 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-4.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
m_bDrawMode = FALSE;
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드 시작
m_bDrawMode = TRUE;
//좌표 저장
m_x1 = m_x2 = point.x;
m_y1 = m_y2 = point.y;
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//최종적인 타원을 그린다
dc.SetROP2(R2_COPYPEN);
m_x2 = point.x;
m_y2 = point.y;
if (GetKeyState(VK_CONTROL)) //control
{
CBrush brush(RGB(255, 0, 0));
dc.SelectObject(&brush);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
else
{
CBrush brush(RGB(255, 255, 255)); //흰색
dc.SelectObject(&brush);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
//그리기 모드를 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드면 타원을 지우고 그리기 반복
if (m_bDrawMode)
{
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//이전에 그린 타원을 지운다
dc.SetROP2(R2_NOT);
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
m_x2 = point.x;
m_y2 = point.y;
dc.Ellipse(m_x1, m_y1, m_x2, m_y2);
}
CWnd::OnMouseMove(nFlags, point);
}
[5-5]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
CPoint coord; //좌표
BOOL onClient; //클라이언트 범위 내에 있는가
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
};
// ChildView.cpp: CChildView 클래스의 구현
//마우스 커서가 클라이언트 영역에 진입하면 타원이 마우스 커서를 따라 다니도록
//ChangeCursor 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-5.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
onClient = FALSE;
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_SETCURSOR()
ON_WM_MOUSEMOVE()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
//dc.SelectStockObject(LTGRAY_BRUSH);
//dc.Ellipse(10, 10, 400, 100);
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
BOOL CChildView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//클라이언트 영역이면 커서 변경
if (nHitTest == HTCLIENT)
{
CPoint point;
::GetCursorPos(&point); //커서 위치(스크린 좌표)를 얻는다
ScreenToClient(&point); //스크린 좌표를 클라이언트 좌표로 변환
CRect rect;
GetClientRect(&rect);
CRgn rgn;
rgn.CreateRectRgn(0, 0, rect.Width(), rect.Height());
if (rgn.PtInRegion(point)) //커서가 리전 안쪽에 있는지 확인
{
onClient = TRUE;
coord.x = point.x;
coord.y = point.y;
}
else
onClient = FALSE;
return TRUE;
}
//클라이언트 영역이 아니면 운영체제가 자동으로 처리
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (onClient == TRUE)
{
CClientDC dc(this);
dc.SelectStockObject(NULL_BRUSH);
//이전에 그린 타원 지운다
dc.SetROP2(R2_NOT);
dc.Ellipse(coord.x - 50, coord.y - 20, coord.x + 50, coord.y + 20);
Sleep(50); //잠깐의 딜레이를 준다
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
dc.Ellipse(coord.x - 50, coord.y - 20, coord.x + 50, coord.y + 20);
}
CWnd::OnMouseMove(nFlags, point);
}
[5-6]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
CPoint coord; //좌표
BOOL click; //왼쪽 버튼을 누른상태인가
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
};
// ChildView.cpp: CChildView 클래스의 구현
//마우스 커서가 타원 위에 올라갔을 때 마우스 왼쪽 버튼을 누르고 드래그 하면
//타원이 이동하고 버튼을 놓으면 멈추도록 ChangeCursor 에제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-6.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
coord.x = coord.y = 50;
click = FALSE;
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_SETCURSOR()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
if (!click)
{
dc.SelectStockObject(LTGRAY_BRUSH);
dc.Ellipse(coord.x - 20, coord.y - 20, coord.x + 20, coord.y + 20);
}
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
click = TRUE;
Invalidate();
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
coord.x = point.x;
coord.y = point.y;
click = FALSE;
Invalidate();
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (click)
{
CClientDC dc(this);
//기존 타원 지우고
dc.SetROP2(R2_NOT);
dc.Ellipse(point.x-20, point.y-20, point.x+20, point.y+20);
Sleep(50); //딜레이
//새로운 타원을 그린다
dc.SetROP2(R2_NOT);
dc.Ellipse(point.x - 20, point.y - 20, point.x + 20, point.y + 20);
}
CWnd::OnMouseMove(nFlags, point);
}
BOOL CChildView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//클라이언트 영역이면 커서를 변경
if (nHitTest == HTCLIENT)
{
CPoint point;
::GetCursorPos(&point); //커서 위치(스크린 좌표)를 얻는다
ScreenToClient(&point); //스크린 좌표를 클라이언트 좌표로 변환
CRgn rgn;
rgn.CreateEllipticRgn(coord.x-20, coord.y-20, coord.x+20, coord.y+20); //타원형 리전 생성
if (rgn.PtInRegion(point)) //커서가 리전 안쪽에 있는지 확인
::SetCursor(AfxGetApp()->LoadCursorW(IDC_CURSOR1));
else
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
return TRUE;
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
[5-7]
// MainFrm.h: CMainFrame 클래스의 인터페이스
//
#pragma once
#include "ChildView.h"
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
// 특성입니다.
public:
BOOL m_bMouseOut;
// 작업입니다.
public:
// 재정의입니다.
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo);
// 구현입니다.
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
CChildView m_wndView;
// 생성된 메시지 맵 함수
protected:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnSetFocus(CWnd *pOldWnd);
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
afx_msg void OnNcMouseLeave();
};
// MainFrm.cpp: CMainFrame 클래스의 구현
//TrackMouse 예제에서 마우스 커서가 비클라이언트 영역에 있으면 300*300
//외부에 있으면 200*200으로 메인 윈도우의 크기가 조절되도록 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-7.h"
#include "MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
ON_WM_SETFOCUS()
ON_WM_NCMOUSEMOVE()
ON_WM_NCMOUSELEAVE()
END_MESSAGE_MAP()
// CMainFrame 생성/소멸
CMainFrame::CMainFrame()
{
// TODO: 여기에 멤버 초기화 코드를 추가합니다.
m_bMouseOut = FALSE;
}
CMainFrame::~CMainFrame()
{
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// 프레임의 클라이언트 영역을 차지하는 뷰를 만듭니다.
if (!m_wndView.Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL))
{
TRACE0("뷰 창을 만들지 못했습니다.\n");
return -1;
}
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: CREATESTRUCT cs를 수정하여 여기에서
// Window 클래스 또는 스타일을 수정합니다.
cs.cx = 200;
cs.cy = 200;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
cs.lpszClass = AfxRegisterWndClass(0);
return TRUE;
}
// CMainFrame 진단
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CFrameWnd::Dump(dc);
}
#endif //_DEBUG
// CMainFrame 메시지 처리기
void CMainFrame::OnSetFocus(CWnd* /*pOldWnd*/)
{
// 뷰 창으로 포커스를 이동합니다.
m_wndView.SetFocus();
}
BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
// 뷰에서 첫째 크랙이 해당 명령에 나타나도록 합니다.
if (m_wndView.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
return TRUE;
// 그렇지 않으면 기본 처리합니다.
return CFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}
void CMainFrame::OnNcMouseMove(UINT nHitTest, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (m_bMouseOut == FALSE)
{
//마우스 커서 추적을 요청
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = this->m_hWnd;
tme.dwHoverTime = HOVER_DEFAULT;
::TrackMouseEvent(&tme);
//메인 윈도우 크기를 300 * 300으로 변경
CWnd *pMainWnd = AfxGetMainWnd();
CRect rect;
pMainWnd->GetWindowRect(&rect);
rect.right = rect.left + 300;
rect.bottom = rect.top + 300;
pMainWnd->MoveWindow(&rect);
//마우스 커서가 클라이언트 영역에 있음을 표시
m_bMouseOut = TRUE;
}
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
void CMainFrame::OnNcMouseLeave()
{
// 이 기능을 사용하려면 Windows 2000 이상이 필요합니다.
// _WIN32_WINNT 및 WINVER 기호는 0x0500보다 크거나 같아야 합니다.
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
m_bMouseOut = FALSE;
//메인 윈도우 크기를 200*200으로 변경
CWnd *pMainWnd = AfxGetMainWnd();
CRect rect;
pMainWnd->GetWindowRect(&rect);
rect.right = rect.left + 200;
rect.bottom = rect.top + 200;
pMainWnd->MoveWindow(&rect);
CWnd::OnMouseLeave();
CFrameWnd::OnNcMouseLeave();
}
[5-8]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
int m_xPos, m_yPos; //도형의 현재 위치
int m_xMax, m_yMax; //클라이언트 영역의 크기
BOOL m_bFill; //도형의 내부를 채울지 여부
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnSize(UINT nType, int cx, int cy);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};
// ChildView.cpp: CChildView 클래스의 구현
//Ctrl 키를 누른 상태로 방향키를 누르면 도형이 두 배 빠르게 이동하도록
//InputKeyStroke 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-8.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
m_xPos = m_yPos = 60; //임의의 값
m_bFill = FALSE; //도형 내부를 채우지 않음
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
// CChildView 메시지 처리기
BOOL CChildView::PreCreateWindow(CREATESTRUCT& cs)
{
if (!CWnd::PreCreateWindow(cs))
return FALSE;
cs.dwExStyle |= WS_EX_CLIENTEDGE;
cs.style &= ~WS_BORDER;
cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
::LoadCursor(NULL, IDC_ARROW), reinterpret_cast<HBRUSH>(COLOR_WINDOW+1), NULL);
return TRUE;
}
void CChildView::OnPaint()
{
CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
if (m_bFill == TRUE)
dc.SelectStockObject(BLACK_BRUSH);
dc.Ellipse(m_xPos - 20, m_yPos - 20, m_xPos + 20, m_yPos + 20);
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
m_xMax = cx;
m_yMax = cy;
}
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
switch (nChar)
{
case VK_LEFT:
m_xPos -= GetKeyState(VK_CONTROL) ? 40 : 20;
break;
case VK_RIGHT:
m_xPos += GetKeyState(VK_CONTROL) ? 40 : 20;
break;
case VK_UP:
m_yPos -= GetKeyState(VK_CONTROL) ? 40 : 20;
break;
case VK_DOWN:
m_yPos += GetKeyState(VK_CONTROL) ? 40 : 20;
break;
case VK_SPACE:
m_bFill = !m_bFill;
}
//20<=m_xPos<=m_xMax-20
m_xPos = min(max(20, m_xPos), m_xMax - 20);
//20<=m_yPos<=m_yMax-20
m_yPos = min(max(20, m_yPos), m_yMax - 20);
Invalidate();
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
개발환경:Visual Studio 2017
지적, 조언, 질문 환영입니다! 댓글 남겨주세요~
'MFC > 윈도우 프로그래밍' 카테고리의 다른 글
MFC 윈도우 프로그래밍 5장 심화문제 (0) | 2018.04.01 |
---|---|
MFC 윈도우 프로그래밍 5장 연습문제(9~16) (0) | 2018.03.30 |
MFC 윈도우 프로그래밍 4장 심화문제 (0) | 2018.03.26 |
MFC 윈도우 프로그래밍 4장 연습문제(9~16) (3) | 2018.03.25 |
MFC 윈도우 프로그래밍 4장 연습문제(1~8) (2) | 2018.03.24 |