윈도우 프로그래밍 Visual C++ 2010 MFC Programming(김선우, 신화서 저) 5장 연습문제입니다.
저번에 이어 나머지 연습문제를 풀어봤습니다.
[5-9]
// 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 클래스의 구현
//Shift 키를 누른 상태로 방향키를 누르면 도형이 반대 방향으로
//이동하도록 InputKey Stroke 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-9.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:
if (GetKeyState(VK_SHIFT)) //Shift In
m_xPos += 20;
else
m_xPos -= 20;
break;
case VK_RIGHT:
if (GetKeyState(VK_SHIFT)) //Shift In
m_xPos -= 20;
else
m_xPos += 20;
break;
case VK_UP:
if (GetKeyState(VK_SHIFT)) //Shift In
m_yPos += 20;
else
m_yPos -= 20;
break;
case VK_DOWN:
if (GetKeyState(VK_SHIFT)) //Shift In
m_yPos -= 20;
else
m_yPos += 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);
}
[5-10]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
#include <afxtempl.h>
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
CArray<TCHAR, TCHAR> m_str;
// 작업입니다.
public:
// 재정의입니다.
protected:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
// 구현입니다.
public:
virtual ~CChildView();
// 생성된 메시지 맵 함수
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
};
// ChildView.cpp: CChildView 클래스의 구현
//클라이언트 영역에 글자를 입력ㅎ하는 부분에 캐럿을 표시하도록 InputCharacter
//예제를 수정하시오.
#include "stdafx.h"
#include "연습문제 5-10.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_CHAR()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
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: 여기에 메시지 처리기 코드를 추가합니다.
//화면 출력용 폰트 선택
CFont font;
font.CreatePointFont(150, _T("궁서"));
dc.SelectObject(&font);
//현재까지 입력된 글자들을 화면에 출력
CRect rect;
GetClientRect(&rect);
dc.DrawText(m_str.GetData(), m_str.GetSize(), &rect, DT_LEFT);
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//[BackSpace]키 입력시 마지막 글자 삭제
CPoint coord = GetCaretPos();
if (nChar == _T('\b'))
{
if (m_str.GetSize() > 0)
m_str.RemoveAt(m_str.GetSize() - 1);
CPoint temp = { coord.x - 10, coord.y };
SetCaretPos(temp);
}
//그 밖의 경우에는 동적 배열에 글자 추가
else
{
m_str.Add(nChar);
if (nChar == 13)
{
CPoint temp = { 0, coord.y + 16 };
SetCaretPos(temp);
}
else
{
CPoint temp = { coord.x + 10, coord.y };
SetCaretPos(temp);
}
}
//화면 갱신
Invalidate();
CWnd::OnChar(nChar, nRepCnt, nFlags);
}
void CChildView::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
CreateSolidCaret(1, 20); //캐럿 생성
ShowCaret(); //화면에 보인다
}
void CChildView::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
// TODO: 여기에 메시지 처리기 코드를 추가합니다.
HideCaret(); //캐럿을 숨긴다
::DestroyCaret(); //캐럿을 파괴
}
[5-11]
// MainFrm.h: CMainFrame 클래스의 인터페이스
//
#pragma once
#include "ChildView.h"
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
// 특성입니다.
public:
// 작업입니다.
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 OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnNcMouseMove(UINT nHitTest, CPoint point);
};
// MainFrm.cpp: CMainFrame 클래스의 구현
//타이틀바 <종료> 버튼에 마우스 커서를 가져가면, 마우스 커서가 윈도우에서
//기본으로 제공되는 금지 모양(IDC_NO)으로 변경되도록 DisableCloseButton 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-11.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()
END_MESSAGE_MAP()
// CMainFrame 생성/소멸
CMainFrame::CMainFrame()
{
// TODO: 여기에 멤버 초기화 코드를 추가합니다.
}
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.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 (nHitTest == HTCLOSE)
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_NO));
else
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
[5-12]
// MainFrm.h: CMainFrame 클래스의 인터페이스
//
#pragma once
#include "ChildView.h"
class CMainFrame : public CFrameWnd
{
public:
CMainFrame();
protected:
DECLARE_DYNAMIC(CMainFrame)
// 특성입니다.
public:
// 작업입니다.
public:
BOOL onClose;
// 재정의입니다.
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);
};
// MainFrm.cpp: CMainFrame 클래스의 구현
//타이틀바의 종료 버튼에 마우스 커서를 가져가면 종료 버튼이 다른 비트맵으로 바뀌고
//마우스 커서를 이동하면 원래 상태로 다시 돌아오도록 DisableCloseButton 예제를 수정하시오
#include "stdafx.h"
#include "연습문제 5-12.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()
END_MESSAGE_MAP()
// CMainFrame 생성/소멸
CMainFrame::CMainFrame()
{
// TODO: 여기에 멤버 초기화 코드를 추가합니다.
onClose = 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.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 (nHitTest == HTCLOSE)
{
CWindowDC dc(this);
CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
BITMAP myBitmap;
bitmap.GetBitmap(&myBitmap);
CDC dcMem;
dcMem.CreateCompatibleDC(&dc);
dcMem.SelectObject(&bitmap);
CRect rect;
GetWindowRect(&rect);
int cxFrame = ::GetSystemMetrics(SM_CXFRAME);
int cyFrame = ::GetSystemMetrics(SM_CYFRAME);
int cxSize = ::GetSystemMetrics(SM_CXSIZE);
int cySize = ::GetSystemMetrics(SM_CYSIZE);
int cxBorder = ::GetSystemMetrics(SM_CXBORDER);
int cyBorder = ::GetSystemMetrics(SM_CYBORDER);
//종료 버튼에 비트맵을 덮어씌우는 방법을 모르겠다
//좌표 위치는 종료 버튼이 맞는데 타이틀바가 무조건 위에 출력되어 비트맵이 출력이 안됩니다
dc.StretchBlt(rect.Width() - cxSize - cxFrame - cxBorder, cyFrame + cyBorder, cxSize, cySize, &dcMem, 0, 0, myBitmap.bmWidth, myBitmap.bmHeight, SRCCOPY);
onClose = TRUE;
}
else if (onClose == TRUE)
{
onClose = FALSE;
RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE);
}
CFrameWnd::OnNcMouseMove(nHitTest, point);
}
[5-13]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
BOOL m_bDrawMode; //그리기 작업이 진행 중
int m_x1, m_x2, m_y1, 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 OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
};
// ChildView.cpp: CChildView 클래스의 구현
//
#include "stdafx.h"
#include "연습문제 5-13.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()
ON_WM_KEYUP()
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);
list.AddTail(CRect(m_x1, m_y1, m_x2, m_y2));
//그리기 모드를 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if(nChar==VK_DELETE)
list.RemoveTail(); // 마지막 타원 지운다
Invalidate();
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
[5-14]
// 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 OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
};
// ChildView.cpp: CChildView 클래스의 구현
//DrawCircles 예제에 insert 키를 누르면 최종적으로 그려진 타원 옆에 타원이 하나 추가되도록 수정하시오
#include "stdafx.h"
#include "연습문제 5-14.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()
ON_WM_KEYUP()
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);
list.AddTail(CRect(m_x1, m_y1, m_x2, m_y2));
//그리기 모드를 끝낸다
m_bDrawMode = FALSE;
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (nChar == VK_INSERT)
{
POSITION pos = list.GetTailPosition();
CRect rect = list.GetPrev(pos);
list.AddTail(CRect(rect.left-50, rect.top-50, rect.left+50, rect.top+50)); //100, 100 움직인 지점
}
Invalidate();
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
[5-15]
// 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<CPoint, CPoint&> 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 OnLButtonUp(UINT nFlags, CPoint point);
};
// ChildView.cpp: CChildView 클래스의 구현
//DrawCircles 예제에 마우스로 자유 곡선을 그리는 기능을 구현하시오
//마우스 왼쪽 버튼을 누르고 드래그하면 마우스 커서 움직임에 따라 선이 그려지고 눌렀던 버튼을 놓으면 선이 끝난다
//단, 자유곡선은 하나만 그릴 수 있다.
#include "stdafx.h"
#include "연습문제 5-15.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();
if (pos)
{
CPoint start = list.GetNext(pos);
dc.MoveTo(start);
}
while (pos)
{
CPoint end = list.GetNext(pos);
dc.LineTo(end);
}
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
list.RemoveAll();
Invalidate();
Sleep(50);
SetCapture(); //마우스 캡처
//그리기 모드
m_bDrawMode = TRUE;
list.AddTail(point);
CWnd::OnLButtonDown(nFlags, point);
}
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드이면 직선을 지우고 그리기 반복
if (m_bDrawMode)
{
CPoint coord = list.GetTail();
list.AddTail(point);
CRect rect(coord.x, coord.y, point.x, point.y);
rect.NormalizeRect();
rect.InflateRect(1, 1); //폭과 높이가 0이 되는 것을 방지
InvalidateRect(rect);
}
CWnd::OnMouseMove(nFlags, point);
}
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
//그리기 모드 해제
m_bDrawMode = FALSE;
::ReleaseCapture(); //마우스 캡쳐 해제
CWnd::OnLButtonUp(nFlags, point);
}
[5-16]
// ChildView.h: CChildView 클래스의 인터페이스
//
#pragma once
// CChildView 창
class CChildView : public CWnd
{
// 생성입니다.
public:
CChildView();
// 특성입니다.
public:
int bitmapSize;
BOOL space;
BOOL alt;
// 작업입니다.
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 OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
};
// ChildView.cpp: CChildView 클래스의 구현
//DrawCircles 예제를 다음과 같이 수정하시오.
//클라이언트 영역에 타원 대신 비트맵을 원본 크기로 출력하되 ctrl+spaceBar+마우스 왼쪽 버튼 클릭이면
//비트맵 크기를 단계적으로 확대하고, ctrl+alt+마우스 왼쪽 버틍ㄴ 클릭이면 비트맵 크기를 단계적으로 축소한다
#include "stdafx.h"
#include "연습문제 5-16.h"
#include "ChildView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CChildView
CChildView::CChildView()
{
bitmapSize = 5;
space = alt = FALSE;
}
CChildView::~CChildView()
{
}
BEGIN_MESSAGE_MAP(CChildView, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_KEYUP()
ON_WM_KEYDOWN()
ON_WM_SYSKEYDOWN()
ON_WM_SYSKEYUP()
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: 여기에 메시지 처리기 코드를 추가합니다.
//비트맵 리소스를 로드한 후 크기 정보를 얻는다
CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);
BITMAP bmpinfo;
bitmap.GetBitmap(&bmpinfo);
//메모리 디바이스 컨텍스트
CDC dcmem;
dcmem.CreateCompatibleDC(&dc);
dcmem.SelectObject(&bitmap);
dc.StretchBlt(0, 0, bitmapSize*bmpinfo.bmWidth, bitmapSize*bmpinfo.bmHeight, &dcmem, 0, 0, bmpinfo.bmWidth, bmpinfo.bmHeight, SRCCOPY);
// 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.
}
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (space == TRUE)
{
if (nFlags & MK_CONTROL) //Ctrl+space+왼쪽 클릭
bitmapSize++;
else if (alt == TRUE) //alt+space+왼쪽 클릭
bitmapSize--;
if (bitmapSize < 1)
bitmapSize = 1;
Invalidate();
}
CWnd::OnLButtonUp(nFlags, point);
}
void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (nChar == VK_SPACE)
space = FALSE;
else if (nChar == VK_MENU)
alt = FALSE;
CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
}
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (nChar == VK_SPACE)
space = TRUE;
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
//Key들이 결합되었을 경우 SysKey
void CChildView::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (nChar == VK_MENU)
alt = TRUE;
else if (nChar == VK_SPACE)
space = TRUE;
CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
}
void CChildView::OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
if (nChar == VK_MENU)
alt = FALSE;
else
space = FALSE;
CWnd::OnSysKeyUp(nChar, nRepCnt, nFlags);
}
개발환경:Visual Studio 2017
지적, 조언, 질문 환영입니다! 댓글 남겨주세요~
'MFC > 윈도우 프로그래밍' 카테고리의 다른 글
MFC 윈도우 프로그래밍 6장 연습문제(1~8) (0) | 2018.04.06 |
---|---|
MFC 윈도우 프로그래밍 5장 심화문제 (0) | 2018.04.01 |
MFC 윈도우 프로그래밍 5장 연습문제(1~8) (0) | 2018.03.29 |
MFC 윈도우 프로그래밍 4장 심화문제 (0) | 2018.03.26 |
MFC 윈도우 프로그래밍 4장 연습문제(9~16) (3) | 2018.03.25 |