코드/MFC

[MFC] 따라하기 05. 여러 개의 원 그리기

야곰야곰+책벌레 2022. 3. 8. 17:06
728x90
반응형

1. 프로젝트 예제에 사용되는 내용

  • 구동하는 시스템 제어하기
  • 여러 시스템 구동하기
 

[MFC] 따라하기 04. 원이 그려지는 동작 만들기

1. 프로젝트 예제에 사용되는 내용 원을 이루는 함수 구하기 ClientDC 2. CClientDC와 Ellipse()를 이용하여 원 그리기 Dialog Based 프로젝트를 만든 뒤, 버튼을 하나 추가하여 클릭으로 원을 그릴 수 있도록

stormpy.tistory.com

2. 시작, 일시정지, 정지 기능 만들기

'04. 원이 그려지는 동작 만들기' 프로젝트를 그대로 가져와서 버튼 3개를 만든다.

3개 모두 클릭 이벤트를 만들어 둔다. 

  • 그리기 : 원을 그리기를 처음부터 시작한다.
  • 일시정지 : 원 그리기를 잠시 멈춘다.
  • 정지 : 그리기를 멈춘다.

우선 그리기를 처음부터 하려면 그려진 원을 지워야 하고, 데이터를 초기화해야 한다.

void CDrawCircleDlg::OnBnClickedDraw()
{
	RedrawWindow();
	cntAngle = 0;
	SetTimer(0, 10, NULL);
}

RedrawWindow()는 다이얼로그를 새로 그려주게 된다. CClientDC로 그렸던 원은 OnPaint에서 다시 그려지지 않으므로 완전히 지워진다.

정지의 경우에는 KillTimer()만으로 그리기를 멈출 수 있다.

void CDrawCircleDlg::OnBnClickedStop()
{
	KillTimer(0);
}

위와 같이 원을 그리는 도중에 멈출 수 있다. 이것을 다시 그리려면 '그리기' 함수에서 처리했던 RedrawWindow()만 제거하면 다시 그리기를 할 수는 있지만 다른 방법을 사용해 보도록 하자.

멤버 변수로 pauseDraw를 추가하여 drawCircle에서 작업을 하지 않도록 수정해 보자.

void CDrawCircleDlg::OnTimer(UINT_PTR nIDEvent)
{
	if (pauseDraw)
		return;
	...

pauseDraw가 true가 되면 그리기를 진행하지 않고 return 되게 만들었다.

일시정지 버튼에서는 pauseDraw의 상태만 바꿔주면 된다.

void CDrawCircleDlg::OnBnClickedPause()
{
	pauseDraw ^= true;
}

Pause는 누를 때마다 true/false를 바꿔주기 위해서 XOR 한다. 현재 Pause상태를 알려주기 위해서 버튼의 Caption을 바꿔준다.

void CDrawCircleDlg::OnBnClickedPause()
{
	pauseDraw ^= true;

	if (pauseDraw)
		SetDlgItemText(IDC_PAUSE, L"재시작");
	else
		SetDlgItemText(IDC_PAUSE, L"일시정지");
}

세 개의 원을 그리기 위해서 원 그리기 함수에 Offset을 매개 변수로 추가하자.

void CDrawCircleDlg::drawCircle(int count, double radius, int vertex, int offset_x)
{
	CClientDC dc(this);
	const double pi = 3.1415926535897932384626433832795; // PI

	// 중심점은 반지름보다 (10, 10) 큰 위치
	double cen_x = radius + 10 + offset_x;
	double cen_y = radius + 10;
	double x, y, radian;

	// 시작 위치로 펜을 옮김
	radian = count * 2 * pi / vertex;
	x = radius * cos(radian) + cen_x;
	y = radius * sin(radian) + cen_y;
	dc.MoveTo(x, y);

	// 원 그리기
	radian = (count + 1) * 2 * pi / vertex;
	x = radius * cos(radian) + cen_x;
	y = radius * sin(radian) + cen_y;
	dc.LineTo(x, y);
}

3개의 원을 그리기 위해서 3개의 카운트를 만들어서 적용하며, 서로 다른 시간에서 EVENT가 발생하는 타이머를 사용하여 그려보기로 한다.

void CDrawCircleDlg::OnTimer(UINT_PTR nIDEvent)
{
	if (pauseDraw)
		return;

	double radius = 50; // 반지름
	int vertex = 365; // 꼭지점

	switch (nIDEvent)
	{
		case 0:
		{
			drawCircle(cntAngle[0]++, radius, vertex, 0 * (2 * radius + 10));
			if (cntAngle[0] > vertex)
				KillTimer(0);
			break;
		}

		case 1:
		{
			drawCircle(cntAngle[1]++, radius, vertex, 1 * (2 * radius + 10));
			if (cntAngle[1] > vertex)
				KillTimer(1);
			break;
		}

		case 2:
		{
			drawCircle(cntAngle[2]++, radius, vertex, 2 * (2 * radius + 10));
			if (cntAngle[2] > vertex)
				KillTimer(2);
			break;
		}
	}

	CDialogEx::OnTimer(nIDEvent);
}

타이머는 이해를 위해서 각각 만들었다.

void CDrawCircleDlg::OnBnClickedDraw()
{
	RedrawWindow();
	ZeroMemory(cntAngle, sizeof(cntAngle));
	SetTimer(0, 5, NULL);
	SetTimer(1, 20, NULL);
	SetTimer(2, 10, NULL);
	pauseDraw = false;
}

그리기를 누르면 세 개의 타이머가 실행되도록 한다. cntAngle을 0으로 만드는 것은 ZeroMemory를 사용했다. 배열의 값을 크기만큼 0으로 만들어 준다.

void CDrawCircleDlg::OnBnClickedStop()
{
	KillTimer(0);
	KillTimer(1);
	KillTimer(2);
}

정지 시에도 세 개의 타이머를 모두 정지 시켜야 한다.

모든 작업이 끝났다면 실행해 보자.

서로 다른 속도로 그리는 것을 확인할 수 있다.

05. 여러 개의 원 그리기.zip
0.13MB

728x90
반응형