MFC/윈도우 프로그래밍

MFC 윈도우 프로그래밍 5장 연습문제(9~16)

꾸준함. 2018. 3. 30. 01:02

윈도우 프로그래밍 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


지적, 조언, 질문 환영입니다! 댓글 남겨주세요~


반응형