MFC/윈도우 프로그래밍

MFC 윈도우 프로그래밍 5장 심화문제

꾸준함. 2018. 4. 1. 10:30

윈도우 프로그래밍 Visual C++ 2010 MFC Programming(김선우, 신화서 저) 5장 심화문제입니다.

2번 3번은 https://blog.naver.com/mark1007/220988574718 참고했습니다.


[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; //타원에 외접하는 직사각형의 좌상단/우하단 좌표

// 작업입니다.

public:

 

// 재정의입니다.

        protected:

        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

 

// 구현입니다.

public:

        virtual ~CChildView();

 

        // 생성된 메시지 맵 함수

protected:

        afx_msg void OnPaint();

        DECLARE_MESSAGE_MAP()

public:

        afx_msg void OnMouseMove(UINT nFlags, CPoint point);

        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

        afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

};

 

  

// ChildView.cpp: CChildView 클래스의 구현

//ChangeCursor 예제를 다음과 같이 수정하시오

//마우스 커서가 타원 위에 올라갔을 때 마우스 왼쪽 버튼을 누르고 드래그하면 타원이 이동하고

//버튼을 놓으면 멈춘다.

//그리고 마우스 왼쪽 버튼을 누른 상태에서 방향키를 사용해 마우스를 1픽셀씩 움직인다

 

#include "stdafx.h"

#include "심화문제 5-1(2).h"

#include "ChildView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

 

// CChildView

 

CChildView::CChildView()

{

        m_bDrawMode = FALSE;

        m_x1 = 10;

        m_y1 = 10;

        m_x2 = 400;

        m_y2 = 100;

}

 

CChildView::~CChildView()

{

}

 

 

BEGIN_MESSAGE_MAP(CChildView, CWnd)

        ON_WM_PAINT()

        ON_WM_MOUSEMOVE()

        ON_WM_LBUTTONDOWN()

        ON_WM_LBUTTONUP()

        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: 여기에 메시지 처리기 코드를 추가합니다.

        dc.SelectStockObject(LTGRAY_BRUSH);

        dc.Ellipse(m_x1, m_y1, m_x2, m_y2);

        // 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.

}

 

 

 

void CChildView::OnMouseMove(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (m_bDrawMode)

        {

               Invalidate();

               CClientDC dc(this);

               dc.SelectStockObject(NULL_BRUSH);

               //이전에 그린 타원 지운다

               dc.SetROP2(R2_NOT);

               dc.Ellipse(m_x1, m_y1, m_x2, m_y2);

               //새로운 타원 그린다

               CPoint cursor;

               ::GetCursorPos(&cursor);

               ScreenToClient(&cursor); //커서의 위치를 클라이언트 좌표로

               dc.SetROP2(R2_NOT);

               m_x1 = cursor.x - 195;

               m_x2 = cursor.x + 195;

               m_y1 = cursor.y - 45;

               m_y2 = cursor.y + 45;

               dc.Ellipse(m_x1, m_y1, m_x2, m_y2);

        }

        CWnd::OnMouseMove(nFlags, point);

}

 

 

void CChildView::OnLButtonDown(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        //그리기 모드 시작

        m_bDrawMode = TRUE;

        //좌표 저장

        m_x1 = point.x - 195;

        m_x2 = point.x + 195;

        m_y1 = point.y - 45;

        m_y2 = point.y + 45;

        CWnd::OnLButtonDown(nFlags, point);

}

 

 

void CChildView::OnLButtonUp(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        CClientDC dc(this);

        //그리기 모드 끝낸다

        m_bDrawMode = FALSE;

        Invalidate();

        CWnd::OnLButtonUp(nFlags, point);

}

 

 

void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        CPoint inside;

        ::GetCursorPos(&inside);

        ScreenToClient(&inside); //커서의 위치를 클라이언트 좌표로

 

        CRgn rgn;

        rgn.CreateEllipticRgn(m_x1, m_y1, m_x2, m_y2);

 

        if (m_bDrawMode && rgn.PtInRegion(inside))

        {

               CPoint cursor;

               ::GetCursorPos(&cursor);

 

               switch (nChar)

               {

               case VK_LEFT:

                       cursor.x--;

                       break;

               case VK_RIGHT:

                       cursor.x++;

                       break;

               case VK_UP:

                       cursor.y--;

                       break;

               case VK_DOWN:

                       cursor.y++;

                       break;

               }

               ::SetCursorPos(cursor.x, cursor.y);

        }

        CWnd::OnKeyDown(nChar, nRepCnt, nFlags);

}

 

[5-2]

 

// ChildView.h: CChildView 클래스의 인터페이스

//

 

 

#pragma once

 

 

// CChildView

 

class CChildView : public CWnd

{

// 생성입니다.

public:

        CChildView();

 

// 특성입니다.

public:

        CString str;

        CRect rect;

        BOOL bCaret;

// 작업입니다.

public:

        CPoint UpdateCaret(BOOL bCalc = FALSE);

// 재정의입니다.

        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 OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);

        afx_msg void OnKillFocus(CWnd* pNewWnd);

};

 

  

// ChildView.cpp: CChildView 클래스의 구현

//ChangeCursor 예제를 다음과 같이 수정하시오.

//클라이언트 영역에 타원 대신 사각ㅎ형을 하나 그린다.

//그리고 마우스로 해당 사각형 내부를 클릭하면 캐럿이 생기고 키보드로 글자를 입력할 수 있다.

 

#include "stdafx.h"

#include "심화문제 5-2.h"

#include "ChildView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

 

// CChildView

 

CChildView::CChildView()

{

        bCaret = FALSE;

        rect = CRect(10, 10, 100, 100);

}

 

CChildView::~CChildView()

{

}

 

 

BEGIN_MESSAGE_MAP(CChildView, CWnd)

        ON_WM_PAINT()

        ON_WM_LBUTTONDOWN()

        ON_WM_CHAR()

        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: 여기에 메시지 처리기 코드를 추가합니다.

        CRect tempRect = rect;

        tempRect.InflateRect(10, 0);

        dc.Rectangle(tempRect);

        dc.DrawText(str, &rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);

        // 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.

}

 

 

//마우스 왼쪽 버튼을 클릭했을 때, 그 위치가 사각형 영역안이면 캐럿 표시

void CChildView::OnLButtonDown(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (rect.PtInRect(point) == TRUE)

        {

               TEXTMETRIC tm;

               CClientDC dc(this);

               dc.GetTextMetrics(&tm);

 

               CreateSolidCaret(2, tm.tmHeight); //캐럿 생성

               ShowCaret(); //화면에 보이도록 한다

               UpdateCaret();

               bCaret = TRUE;

        }

        else

        {

               HideCaret();

               ::DestroyCaret();

               bCaret = FALSE;

        }

        CWnd::OnLButtonDown(nFlags, point);

}

 

//캐럿의 위치를변경하는 함수

//캐럿의 위치를 결정하기 위해 출력할 공간을 먼저 계산한 ㅎ후 이동

//CDC 클래스의 GetTextMetrics() 함수는 현재 폰트의 정보를 TEXTMETRIC 구조체 형태로 알려줌

CPoint CChildView::UpdateCaret(BOOL bCalc)

{

        TEXTMETRIC tm;

        CClientDC dc(this);

        dc.GetTextMetrics(&tm);

 

        CRect tempRect = rect;

        CPoint coord = tempRect.CenterPoint();

       

        if (str.IsEmpty() == FALSE)

        {

               dc.DrawText(str, tempRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE);

               coord.x = tempRect.right;

        }

        else

               coord.x = tempRect.left;

 

        coord.y -= tm.tmHeight / 2;

 

        if (bCalc == FALSE)

               SetCaretPos(coord); //위치설정

        return coord;

}

 

//키보드입력을 받는다

//UpdateCaret() 함수를 사용ㅎ하여 영역을 벗어나는지 검사

void CChildView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (nChar >= 32 && bCaret == TRUE)

        {

               CString strBackup;

               strBackup = str;

               str += (char)nChar;

 

               //영역 벗어나는지 검사

               CPoint inside = UpdateCaret(TRUE);

               if (rect.PtInRect(inside) == FALSE)

                       str = strBackup;

               UpdateCaret();

               Invalidate();

        }

        CWnd::OnChar(nChar, nRepCnt, nFlags);

}

 

 

void CChildView::OnKillFocus(CWnd* pNewWnd)

{

        CWnd::OnKillFocus(pNewWnd);

        HideCaret();

        ::DestroyCaret();

        // TODO: 여기에 메시지 처리기 코드를 추가합니다.

}

 

[5-3]

 

// ChildView.h: CChildView 클래스의 인터페이스

//

 

 

#pragma once

 

 

// CChildView

 

class CChildView : public CWnd

{

// 생성입니다.

public:

        CChildView();

 

// 특성입니다.

public:

        CString m_str;

        CPoint m_ptCaret;

// 작업입니다.

public:

        CPoint UpdateCaret(int index = -1, BOOL bCalc = FALSE);

        CString FindRowString(CString &str, DWORD dwRow, int *indexFound = NULL);

// 재정의입니다.

        protected:

               CPoint GetCaretPoint(int index = -1);

               int GetCharIndex(CPoint point);

               int GetVertCharIndex(CPoint point, BOOL bUpward);

        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

 

// 구현입니다.

public:

        virtual ~CChildView();

 

        // 생성된 메시지 맵 함수

protected:

        afx_msg void OnPaint();

        DECLARE_MESSAGE_MAP()

public:

        afx_msg void OnSetFocus(CWnd* pOldWnd);

        afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);

        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

        afx_msg void OnKillFocus(CWnd* pNewWnd);

};

 

  

// ChildView.cpp: CChildView 클래스의 구현

//캐럿을 표시하고 방향키를 사용하여 입력한 문자 내에서

//이동할 수 있도록 inputCharacter 예제를 수정하시오

 

#include "stdafx.h"

#include "심화문제 5-3.h"

#include "ChildView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

 

// CChildView

 

CChildView::CChildView()

{

        m_ptCaret = CPoint(0, 0);

}

 

CChildView::~CChildView()

{

}

 

 

BEGIN_MESSAGE_MAP(CChildView, CWnd)

        ON_WM_PAINT()

        ON_WM_SETFOCUS()

        ON_WM_CHAR()

        ON_WM_KEYDOWN()

        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: 여기에 메시지 처리기 코드를 추가합니다.

        CRect rect;

        GetClientRect(&rect);

        dc.DrawText(m_str, &rect, DT_LEFT | DT_TOP);

        // 그리기 메시지에 대해서는 CWnd::OnPaint()를 호출하지 마십시오.

}

 

 

//OnSetFocus() 함수에서 포커스를 받을 때 캐럿을 화면에 보이도록 처리

void CChildView::OnSetFocus(CWnd* pOldWnd)

{

        CWnd::OnSetFocus(pOldWnd);

 

        // TODO: 여기에 메시지 처리기 코드를 추가합니다.

        TEXTMETRIC tm;

        CClientDC dc(this);

        dc.GetTextMetrics(&tm);

 

        CreateSolidCaret(2, tm.tmHeight); //캐럿 생성

        ShowCaret(); //화면에 보이도록 한다

        SetCaretPos(m_ptCaret);

}

 

//키보드 입력 문자 처리

//현재 문자를 입력하는 위치가 문장의 끝이면 m_str 멤버 변수에 현재 문자 추가

//문자 중간이면 덮어쓰기 모드로 처리하여 해당 문자를 새로운 문자로 교체

void CChildView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (nChar >= 32)

        {

               int idx = GetCharIndex(m_ptCaret);

               if (idx == m_str.GetLength())

               {

                       m_str += (char)nChar;

                       m_ptCaret = UpdateCaret();

               }

               else

               {

                       //덮어쓰기

                       m_str.Format(_T("%s%c%s"), m_str.Left(idx), nChar, m_str.Mid(idx + 1));

                       m_ptCaret = UpdateCaret(idx + 1);

               }

               Invalidate();

        }

        CWnd::OnChar(nChar, nRepCnt, nFlags);

}

 

//GetCharIndex() 함수는 현재의 위치를 m_str 멤버 변수 문자열의 인덱스로 계산해 주는 함수

//먼저 폰트 높이를 이용해 몇 번째 줄인지 찾아내고 FindRowString() 멤버 함수로 해당 줄의 문자열을 알아낸다

//그 문자열을 한 줄로 출력해 보면서 현재 위치와 비교하여 인덱스 계산

int CChildView::GetCharIndex(CPoint point)

{

        TEXTMETRIC tm;

        CClientDC dc(this);

        dc.GetTextMetrics(&tm);

 

        CRect rect;

        GetClientRect(rect);

 

        DWORD dwRow = point.y / tm.tmHeight;

        int idx = 0;

        CString str = FindRowString(m_str, dwRow, &idx);

 

        if (str.IsEmpty() == TRUE)

               return idx;

        if (point.x == 0)

               return idx;

 

        CString strFraction;

        CPoint coord(point);

        CRect rectCalc;

 

        for (int i = 1; i <= str.GetLength(); i++)

        {

               rectCalc = rect;

               strFraction = str.Left(i);

 

               dc.DrawText(strFraction, rectCalc, DT_CALCRECT | DT_LEFT | DT_TOP | DT_SINGLELINE);

               if (point.x == rectCalc.right)

                       return idx + i;

        }

        return -1;

}

 

CString CChildView::FindRowString(CString &str, DWORD dwRow, int *indexFound)

{

        int idx = 0, idxNext = -1;

 

        for (DWORD i = 0; i <= dwRow; i++)

        {

               idx = idxNext + 1;

                idxNext = str.Find(VK_RETURN, idx);

        }

 

        if (idxNext == -1)

               idxNext = str.GetLength();

        if (indexFound != NULL)

               *indexFound = idx;

 

        return str.Mid(idx, idxNext - idx);

}

 

//GetVertCharIndex() 함수는 상하로 이동할 때 이동할 위치를 문자열 인덱스로 리턴하는 함수

//폰트가 고정폭인 경우에는 상하 이동이 크게 어렵지 않지만, 가변폭인 경우는 가장 가까운쪽으로 예측해야한다

//그 때문에 다음과 같이 행은 폰트 높이로 비교적 간단히 계산, 가로 위치는 현 위치, , 뒤로 검색해야한다

//또한 해당 위치에 글자가 없으면 그 행의 가장 끝으로 이동하는 루틴도 필요하다

int CChildView::GetVertCharIndex(CPoint point, BOOL bUpward)

{

        TEXTMETRIC tm;

        CClientDC dc(this);

        dc.GetTextMetrics(&tm);

 

        CRect rect;

        GetClientRect(rect);

 

        CPoint coord(point);

        if (bUpward == TRUE)

        {

               coord.y -= tm.tmHeight;

               if (coord.y < 0)

                       return -1;

        }

        else

        {

               coord.y += tm.tmHeight;

 

               CRect rectCalc(rect);

               dc.DrawText(m_str, rectCalc, DT_CALCRECT | DT_LEFT | DT_TOP);

               if (coord.y > rectCalc.bottom - tm.tmHeight)

                       return -1;

        }

 

        int dx = tm.tmAveCharWidth / 2;

        for (int i = coord.x; i >= coord.x - dx; i--) //중간에서 앞쪽 검색

        {

               CPoint coordSearch(i, coord.y);

               int idx = GetCharIndex(coordSearch);

               if (idx != -1)

                       return idx;

        }

        for (int i = coord.x + 1; i <= coord.x + dx; i++) //뒤쪽 검색

        {

               CPoint coordSearch(i, coord.y);

               int idx = GetCharIndex(coordSearch);

               if (idx != -1)

                       return idx;

        }

 

        //행 끝으로 이동

        DWORD dwRow = coord.y / tm.tmHeight;

        int idx = 0;

        CString str = FindRowString(m_str, bUpward ? dwRow++ : dwRow--, &idx);

 

        return idx + str.GetLength();

}

 

//UpdateCaret() 함수는 인덱스로 캐럿의 위치를 계산한 후 캐럿의 위치를 변경하는 함수

//변경된 위치를 리턴하기 때문에 현재 위치를 갱신할 때 사용, 두번째 인자를 TRUE로 입력하면 계산 전용

CPoint CChildView::UpdateCaret(int idx, BOOL bCalc)

{

        CPoint coord = GetCaretPoint(idx);

        if (bCalc == FALSE)

               SetCaretPos(coord); //위치 설정

 

        return coord;

}

 

//GetCaretPoint() 함수는 이전의 GetCharIndex() 함수와 반대로, m_str 멤버 변수의 문자열 인덱스를 주면 화면의 좌표를 리턴하는 함수

//DrawText() 함수로 먼저 전체를 출력하여 현재 y 좌표 계산, FindRowString() 함수로 해당 줄의 문자열을 추출하여 그를 통해 x 좌표 계산

CPoint CChildView::GetCaretPoint(int idx)

{

        TEXTMETRIC tm;

        CClientDC dc(this);

        dc.GetTextMetrics(&tm);

 

        CRect rect;

        GetClientRect(&rect);

        CPoint coord(0, 0);

       

        CString str = (idx == -1) ? m_str : m_str.Left(idx);

        CRect rectCalc(rect);

 

        if (str.IsEmpty() == FALSE)

        {

               dc.DrawText(str, rectCalc, DT_CALCRECT | DT_LEFT | DT_TOP);

               coord.y = rectCalc.bottom - tm.tmHeight;

 

               CString strRow = FindRowString(str, coord.y / tm.tmHeight);

               if (strRow.IsEmpty() == FALSE)

               {

                       rectCalc = rect;

                       dc.DrawText(strRow, rectCalc, DT_CALCRECT | DT_LEFT | DT_TOP | DT_SINGLELINE);

                       coord.x = rectCalc.right;

               }

               else

                       coord.x = 0;

        }

        return coord;

}

 

//화살표 키를 눌렀을 떄 캐럿 이동 처리

//좌우의 경우 GetCharIndex() 함수로 전달받은 인덱스를 감소 또는 증가시킨 후

//UpdateCaret() 함수로 적용시킨다

//상하의 경우 GetVertCharIndex() 함수를 사용하여 이동할 문자열 인덱스를 얻은 후 UpdateCaret() 함수를 적용

void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        int idx = -1;

 

        switch (nChar)

        {

        case VK_LEFT:

               idx = GetCharIndex(m_ptCaret);

               idx--;

               if (idx < 0)

                       idx = 0;

               m_ptCaret = UpdateCaret(idx);

               break;

        case VK_RIGHT:

               idx = GetCharIndex(m_ptCaret);

               idx++;

               if (idx > m_str.GetLength())

                       idx = m_str.GetLength();

               m_ptCaret = UpdateCaret(idx);

               break;

        case VK_UP:

               idx = GetVertCharIndex(m_ptCaret, TRUE);

               if (idx != -1)

                       m_ptCaret = UpdateCaret(idx);

               break;

        case VK_DOWN:

               idx = GetVertCharIndex(m_ptCaret, FALSE);

               if (idx != -1)

                       m_ptCaret = UpdateCaret(idx);

               break;

        }

 

        if (nChar == VK_RETURN)

        {

               int idx = GetCharIndex(m_ptCaret);

               if (idx == m_str.GetLength())

               {

                       m_str += (char)nChar;

                       m_ptCaret = UpdateCaret();;

               }

               else

               {

                       //삽입 모드

                       m_str.Format(_T("%s%c%s", m_str.Left(idx), nChar, m_str.Mid(idx)));

                       m_ptCaret = UpdateCaret(idx + 1);

               }

               Invalidate();

        }

        CWnd::OnKeyDown(nChar, nRepCnt, nFlags);

}

 

 

void CChildView::OnKillFocus(CWnd* pNewWnd)

{

        CWnd::OnKillFocus(pNewWnd);

        HideCaret(); //숨기고

        ::DestroyCaret(); //파괴한다

        // TODO: 여기에 메시지 처리기 코드를 추가합니다.

}

 

[5-4]

 

// ChildView.h: CChildView 클래스의 인터페이스

//

 

 

#pragma once

 

 

// CChildView

 

class CChildView : public CWnd

{

// 생성입니다.

public:

        CChildView();

 

// 특성입니다.

public:

        BOOL m_bDrawMode; //그리기 모드

        BOOL click, ctrl;

        int m_x1, m_y1, m_x2, m_y2;

        CList<CRect, CRect&> 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 OnLButtonUp(UINT nFlags, CPoint point);

        afx_msg void OnMouseMove(UINT nFlags, CPoint point);

        afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

        afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);

};

 

  

// ChildView.cpp: CChildView 클래스의 구현

//ChangeCursor 예제를 다음과 같이 수정하시오

//마우스가 타원 위에 올라갔을 때 마우스 왼쪽 버튼을 누르고 드래긓하면 점선으로 된 타원이 그려지고

//버튼을 놓으면 이동을 끝낸다.

//그리고 ctrl 키를 누른 상태면 복사를 수행하고, 그렇지 않은 상태에서는 이동을 수행한다

 

#include "stdafx.h"

#include "심화문제 5-4.h"

#include "ChildView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

 

// CChildView

 

CChildView::CChildView()

{

        m_bDrawMode = FALSE;

        ctrl = click = FALSE;

        m_x1 = m_y1 = 10;

        m_x2 = 400;

        m_y2 = 100;

        list.AddTail(CRect(m_x1, m_y1, m_x2, m_y2));

}

 

CChildView::~CChildView()

{

        list.RemoveAll();

}

 

 

BEGIN_MESSAGE_MAP(CChildView, CWnd)

        ON_WM_PAINT()

        ON_WM_LBUTTONDOWN()

        ON_WM_LBUTTONUP()

        ON_WM_MOUSEMOVE()

        ON_WM_KEYDOWN()

        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: 여기에 메시지 처리기 코드를 추가합니다.

        dc.SelectStockObject(LTGRAY_BRUSH);

        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 = point.x - 195;

        m_x2 = point.x + 195;

        m_y1 = point.y - 45;

        m_y2 = point.y + 45;

        CWnd::OnLButtonDown(nFlags, point);

}

 

 

void CChildView::OnLButtonUp(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (ctrl)

               list.AddTail(CRect(m_x1, m_y1, m_x2, m_y2));

        else

        {

               list.RemoveAll();

               list.AddTail(CRect(m_x1, m_y1, m_x2, m_y2));

        }

        m_bDrawMode = FALSE;

        Invalidate();

        CWnd::OnLButtonUp(nFlags, point);

}

 

 

void CChildView::OnMouseMove(UINT nFlags, CPoint point)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (m_bDrawMode && click == FALSE)

        {

               CClientDC dc(this);

               CPen pen(PS_DASH, 1, RGB(0, 0, 0));

               dc.SelectObject(&pen);

               dc.SelectStockObject(NULL_BRUSH);

               //이전에 그린 타원 지운다

               dc.SetROP2(R2_NOT);

               dc.Ellipse(m_x1, m_y1, m_x2, m_y2);

               //새로운 타원 그린다

               CPoint cursor;

               ::GetCursorPos(&cursor);

               ScreenToClient(&cursor); //커서의 위치를 클라이언트 좌표로

               dc.SetROP2(R2_NOT);

               m_x1 = cursor.x - 195;

               m_x2 = cursor.x + 195;

               m_y1 = cursor.y - 45;

               m_y2 = cursor.y + 45;

               dc.Ellipse(m_x1, m_y1, m_x2, m_y2);

        }

        CWnd::OnMouseMove(nFlags, point);

}

 

 

void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (nChar == VK_CONTROL)

               ctrl = TRUE;

        CWnd::OnKeyDown(nChar, nRepCnt, nFlags);

}

 

 

void CChildView::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)

{

        // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.

        if (nChar == VK_CONTROL)

               ctrl = FALSE;

        CWnd::OnKeyUp(nChar, nRepCnt, nFlags);

}

 

개발환경:Visual Studio 2017


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

반응형