본문 바로가기
Development Solutions/MFC

[MFC][2] Declare classes to shape and clear (클래스 선언하여 도형 그리고 지우기)

by Dev Diary Hub 2022. 8. 20.
반응형

[MFC][2]

Declare classes to shape and clear

클래스 선언하여 도형 그리고 지우기

 

2022.08.20 - [Development Solutions/MFC] - [MFC][1] To save click coordinates using a CList class (CList 클래스를 이용한 클릭 좌표 저장하기)

 

[MFC][1] To save click coordinates using a CList class (CList 클래스를 이용한 클릭 좌표 저장하기)

[MFC][1] To save click coordinates using a CList class CList 클래스를 이용한 클릭 좌표 저장하기 왼쪽 마우스 클릭한 경우 클릭한 위치와 시간 간격을 알림 창으로 출력하고, 오른쪽 마우스 클릭한 경..

studiodoc.tistory.com

 

 

(추천) Qt QML과 C++로 시작하는 크로스플랫폼 앱 개발 강의 - 입문편

https://inf.run/3XmSH

 

Qt QML과 C++로 시작하는 크로스플랫폼 앱 개발 - 입문편 강의 - 인프런

Qt QML과 C++를 사용하여 크로스플랫폼 애플리케이션 개발에 입문할 수 있습니다. 해당 강의에서는 윈도우 응용 프로그램 타겟으로 개발을 진행합니다., 강의 주제 📖 이 강의를 통해 참가자들은

www.inflearn.com

 

 

 

새로 선언한 MyDraw 클래스를 이용하여 다음과 같이 구현합니다.

 

왼쪽 마우스를 클릭 down 해서 움직인 후 up하여 지정한 범위에 타원, 직사각형, X모양 중 하나를 그리도록 합니다.

오른쪽 마우스 클릭한 경우 세가지 모양 중 하나로 순서대로 도형 모양을 바꿉니다.

키보드 입력으로 'D'가 입력될 경우 왼쪽 마우스로 그렸던 도형 중 하나를 선택하여 삭제할 수 있도록 합니다.

 

[English](Implement the following using the newly declared MyDraw class:
Click down to move the left mouse and up to draw one of the ellipses, rectangles, and X shapes in the specified range.
If you right-click, replace the shapes in order with one of three shapes.
If 'D' is entered as a keyboard input, select one of the shapes you drew with the left mouse to delete.)

반응형

 

- ChildView.cpp

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// ChildView.cpp : CChildView 클래스의 구현
//
 
#include "stdafx.h"
#include "Lab5.h"
#include "ChildView.h"
 
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
 
 
// CChildView
 
CChildView::CChildView()
{
    CList<CMyDraw, CMyDraw&> m_pics; // 리스트 생성
    m_bDraw = false//그릴건지 아닌지
    m_bErase = false//지울건지 아닌지
    m_flag = 0;// Default 0=Rectangle. 1=타원. 2=X-Line
}
 
CChildView::~CChildView()
{
    m_pics.RemoveAll(); //리스트 메모리 반환
}
 
 
BEGIN_MESSAGE_MAP(CChildView, CWnd)
    ON_WM_PAINT()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    ON_WM_RBUTTONDOWN()
    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()를 호출하지 마십시오.
 
    POSITION pos = m_pics.GetHeadPosition();
 
    while (pos!=NULL)
    {
        CMyDraw temp = m_pics.GetNext(pos);
        dc.SelectStockObject(LTGRAY_BRUSH);
 
        if (temp.GetFlag() == 0)// 사각형
        {
            dc.Rectangle(temp.GetStartPoint()->x, temp.GetStartPoint()->y, temp.GetEndPoint()->x, temp.GetEndPoint()->y);
        }
        if (temp.GetFlag() == 1)// 타원
        {
            dc.Ellipse(temp.GetStartPoint()->x, temp.GetStartPoint()->y, temp.GetEndPoint()->x, temp.GetEndPoint()->y);
        }
        if (temp.GetFlag() == 2)// X라인
        {
            dc.MoveTo(temp.GetStartPoint()->x, temp.GetStartPoint()->y);
            dc.LineTo(temp.GetEndPoint()->x, temp.GetEndPoint()->y);
            dc.MoveTo(temp.GetStartPoint()->x, temp.GetEndPoint()->y);
            dc.LineTo(temp.GetEndPoint()->x, temp.GetStartPoint()->y);
        }
 
    }
}
 
 
void CChildView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    
    if (m_bErase) // 지우기 모드 (D눌렀을 경우)
    {
        POSITION pos = m_pics.GetHeadPosition(); // 리스트의 헤드포지션
 
        while (pos != NULL)
        {
            POSITION oldpos = pos; // 삭제하기 위해 GetNext호출 전 pos값 백업
            CMyDraw temp = m_pics.GetNext(pos); //현재 가리키고 있는 리스트 노드
 
            // temp와 같은 좌상단,우하단 점을 갖는 사각형 rtmp
            CRect rtmp(temp.GetStartPoint()->x, temp.GetStartPoint()->y, temp.GetEndPoint()->x, temp.GetEndPoint()->y); 
            rtmp.NormalizeRect(); // 사각형 정규화->높이와 너비 양수화
 
            // 사각형 rtmp 영역 안에 좌클릭한 point가 들어있을 경우
            if (rtmp.PtInRect(point)) 
            {
                m_pics.RemoveAt(oldpos);
                break// 여러 도형이 겹쳐있는 경우 먼저 생성된 도형부터 삭제
            }
        }
    }
    else
    {
        m_start = point;
        m_end = point;
        m_bDraw = TRUE;
 
 
        SetCapture();
        SetCursor(AfxGetApp()->LoadCursorW(IDC_CURSOR1)); // 윈도우 어플리케이션의 포인터로부터 LoadStandardCursor가져다 씀
    }
 
    CWnd::OnLButtonDown(nFlags, point);
}
 
 
void CChildView::OnLButtonUp(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    // 좌클릭을 해서 도형을 삭제하고 나면 그리기모드 off
    if (m_bErase) 
    {
        m_bErase = FALSE;
    }
    else
    {
        m_end = point;
        m_bDraw = FALSE;
        CMyDraw temp;
 
        ReleaseCapture();
        temp.SetStartPoint(m_start);
        temp.SetEndPoint(m_end);
        temp.SetFlag(m_flag);
 
        m_pics.AddTail(temp);
    }
 
    Invalidate(); //그려라!
 
    CWnd::OnLButtonUp(nFlags, point);
}
 
 
void CChildView::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    // 그리기 모드면 타원을 지우고 그리기를 반복한다.
    if (m_bDraw)
    {
        CClientDC dc(this);
        dc.SelectStockObject(LTGRAY_BRUSH);
 
        if (m_flag == 0)// 사각형
        {// 이전에 그린 타원을 지운다.
            dc.SetROP2(R2_NOTXORPEN); //같으면 지워지고 다르면 안지워짐(0)
            dc.Rectangle(m_start.x, m_start.y, m_end.x, m_end.y);
            // 새로운 타원을 그린다.
            dc.SetROP2(R2_NOTXORPEN);
            m_end = point;
            dc.Rectangle(m_start.x, m_start.y, m_end.x, m_end.y);
        }
        if (m_flag == 1)// 타원
        {// 이전에 그린 타원을 지운다.
            dc.SetROP2(R2_NOTXORPEN); //같으면 지워지고 다르면 안지워짐(0)
            dc.Ellipse(m_start.x, m_start.y, m_end.x, m_end.y);
            // 새로운 타원을 그린다.
            dc.SetROP2(R2_NOTXORPEN);
            m_end = point;
            dc.Ellipse(m_start.x, m_start.y, m_end.x, m_end.y);
        }
        if (m_flag == 2)// X라인
        {// 이전에 그린 타원을 지운다.
            dc.SetROP2(R2_NOTXORPEN); //같으면 지워지고 다르면 안지워짐(0)
            //dc.Rectangle(m_start.x, m_start.y, m_end.x, m_end.y);
            dc.MoveTo(m_start.x, m_start.y);
            dc.LineTo(m_end.x, m_end.y);
            dc.MoveTo(m_start.x, m_end.y);
            dc.LineTo(m_end.x, m_start.y);
            // 새로운 타원을 그린다.
            dc.SetROP2(R2_NOTXORPEN);
            m_end = point;
            //dc.Rectangle(m_start.x, m_start.y, m_end.x, m_end.y);
            dc.MoveTo(m_start.x, m_start.y);
            dc.LineTo(m_end.x, m_end.y);
            dc.MoveTo(m_start.x, m_end.y);
            dc.LineTo(m_end.x, m_start.y);
        }
    }
 
    CWnd::OnMouseMove(nFlags, point);
}
 
 
void CChildView::OnRButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    // 우클릭시, 3가지 종류의 도형 전환
    m_flag++;
    if (m_flag > 2)
    {
        m_flag = 0;
    }
    
 
    CWnd::OnRButtonDown(nFlags, point);
}
 
 
void CChildView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 
    // 키보드 D 누르면 도형 지우기 모드 on
    if (nChar == 'D')
    {
        m_bErase = TRUE;
    }
 
    CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
 
cs

 

- ChildView.h

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
// ChildView.h : CChildView 클래스의 인터페이스
//
 
 
#pragma once
#include <afxtempl.h>
#include "MyDraw.h"
 
 
// CChildView 창
 
class CChildView : public CWnd
{
// 생성입니다.
public:
    CChildView();
 
// 특성입니다.
public:
    CList <CMyDraw, CMyDraw&> m_pics; //그림 저장을 위한 배열
    bool m_bDraw, m_bErase;
    int m_flag;
    CPoint m_start, m_end;
 
// 작업입니다.
public:
 
// 재정의입니다.
    protected:
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
 
// 구현입니다.
public:
    virtual ~CChildView();
 
    // 생성된 메시지 맵 함수
protected:
    afx_msg void OnPaint();
    DECLARE_MESSAGE_MAP()
public:
//    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    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 OnRButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};
 
 
cs

 

- MyDraw.cpp

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include "stdafx.h"
#include "MyDraw.h"
 
 
CMyDraw::CMyDraw()
{
    m_type = 0// Default 0=Rectangle. 1=타원. 2=X-Line
}
 
 
CMyDraw::~CMyDraw()
{
}
 
void CMyDraw::SetStartPoint(CPoint st)
{
    m_start = st;
    m_rect.TopLeft() = st;
}
 
CPoint* CMyDraw::GetStartPoint()
{
    return &m_start;
}
 
void CMyDraw::SetEndPoint(CPoint ed)
{
    m_end = ed;
    m_rect.BottomRight() = ed;
}
 
CPoint* CMyDraw::GetEndPoint()
{
    return &m_end;
}
 
CMyDraw& CMyDraw::operator=(const CMyDraw& t)
{
    m_start = t.m_start;
    m_end = t.m_end;
    m_type = t.m_type;
 
    return *this;
}
 
void CMyDraw::SetFlag(int fg)
{
    m_type = fg;
}
 
int CMyDraw::GetFlag()
{
    return m_type;
}
 
CRect& CMyDraw::GetRect()
{
    return m_rect;
}
cs

 

- MyDraw.h

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#pragma once
 
class CMyDraw
{
public:
    CMyDraw();
    ~CMyDraw();
    void SetStartPoint(CPoint st);
    void SetEndPoint(CPoint ed);
    CPoint *GetStartPoint();
    CPoint * GetEndPoint();
    CMyDraw& operator=(const CMyDraw &t);
    void SetFlag(int fg);
    int GetFlag();
    CRect& CMyDraw::GetRect();
 
private:
    CPoint m_start, m_end;
    CRect m_rect; // 왼쪽 마우스 클릭 시작 점과 끝의 점을 저장
    int m_type; // Default 0=Rectangle. 1=타원. 2=X-Line
};
 
 
cs

 

(추천) Qt QML과 C++로 시작하는 크로스플랫폼 앱 개발 강의 - 입문편

https://inf.run/3XmSH

 

Qt QML과 C++로 시작하는 크로스플랫폼 앱 개발 - 입문편 강의 - 인프런

Qt QML과 C++를 사용하여 크로스플랫폼 애플리케이션 개발에 입문할 수 있습니다. 해당 강의에서는 윈도우 응용 프로그램 타겟으로 개발을 진행합니다., 강의 주제 📖 이 강의를 통해 참가자들은

www.inflearn.com

 

반응형