MFC/윈도우 프로그래밍

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

꾸준함. 2018. 3. 29. 02:38

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


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

반응형