본문 바로가기

TIPS/MFC

[TIPS] 11th 20160808

11번째 강좌정리입니다~!



<오목_(2)>

지난번에는 오목판 만들기, 오목돌 칸에 맞춰놓기 까지 작성하였다.

여기까지는 

오목판 바깥에도 돌을 놓을 수 있고,

모니터 바깥으로 창을 옮겼다 가져오면 돌이 없어져 판을 엎을 수 있고...!!

놓았던 곳에 중복해서 또 놓을 수 있는 문제점이 있다.




-돌의 위치 기억하기


1.먼저 놓인 돌의 위치를 기억해주기 위해 Dlg 헤더파일에 들어가 돌이 놓일 수 있는 13*13배열을 선언해준다.


char m_dol[13][13];


2. 그 후 헤더파일에서  '표준생성자입니다' 부분 (여기서는 파일명이 Omok이라서 COmokDlg)을 클릭하고 F12를 눌러 소스파일의 객체생성자 부분을 찾아가 선언한 배열을 모두 0으로 초기화한다. (0은 비어있음, 1은 흑돌, 2는 백돌)


memset(m_dol, 0, sizeof(m_dol));


-돌 두는 곳 오목판으로 제한하기


3. 소스파일에 OnLButtonDown부분으로 돌아와 코드를 수정한다.


int y의 다음 줄부터 'CDialogEx::OnLButtonDown(nFlags, point);'전 줄까지 모두 if문으로 묶어준다.


if (x > 0 && x <= 13 && y > 0 && y <= 13) {

if (m_dol[y - 1][x - 1] > 0) return; // 0이상 즉 백돌이나 흑돌이 존재한다면 새로운 돌을 그리지 않고 return하여 if문을 빠져나온다.

m_dol[y - 1][x - 1] = m_dol_state + 1; //m_dol_state변수를 정할 때 0 : 흑, 1: 백으로 정하였기 때문에 각각 +1을 하여 m_dol 이차원배열에 1또는 2를 저장한다.

......나머지는 그 전에 작성한 코드

}


-'판 엎기' 수정하기


4. 온페인트를 수정해준다.


for (int y = 1; y <= 13; y++) {

for (int x = 1; x <= 13; x++) {

if (m_dol[y - 1][x - 1]>0) {    //돌이 놓아져 있다면,

CBrush *p_old_brush;

if (m_dol[y - 1][x - 1] == 1) { //흑돌을 둘 차례라면,

p_old_brush = (CBrush *)dc.SelectStockObject(BLACK_BRUSH);

}

else { //백돌을 둘 차례라면,

p_old_brush = (CBrush *)dc.SelectStockObject(WHITE_BRUSH);

}

dc.Ellipse(x * 40 - 20, y * 40 - 20, x * 40 + 20, y *40 + 20);

dc.SelectObject(p_old_brush);

}

}

}


5. 여기서 위 코드와 달리 for문 전에 old brush를 미리 받아두고, 선택만 하도록 할 수도 있다. 이렇게 작성한다면 계속 새로 저장하는 일을 하지 않아도 된다.


CBrush *p_old_brush = (CBrush *)dc.SelectStockObject(BLACK_BRUSH);

for (int y = 1; y <= 13; y++) {

for (int x = 1; x <= 13; x++) {

if (m_dol[y - 1][x - 1]>0) { //돌이 놓아져 있느냐

if (m_dol[y - 1][x - 1] == 1) { //흑돌

dc.SelectStockObject(BLACK_BRUSH);

}

else { //백돌

dc.SelectStockObject(WHITE_BRUSH);

}

dc.Ellipse(x * 40 - 20, y * 40 - 20, x * 40 + 20, y *40 + 20);

}

}

}

dc.SelectObject(p_old_brush);



이것으로 오목 끝!

(승리판단에서 if문 하나 없이 모서리부분도 해결하며 판단할 수 있다. 이 부분은 좀 더 생각해보도록 하자.)




MFC로 간단한 덧셈 프로그램 만들기


1. 우선 MFC 프로젝트를 앞서 했던 것과 같이 만들어 준다.


2. 도구상자에 edit control한번만 클릭한다.


3. 대화상자에 배치해준다.

이렇게 한번 생성해주면 resource.h에 #define IDC_EDIT1 101가 생성된다.

만약 지웠다가 다시 만들면  IDC_EDIT2로 만들어지게 된다. 따라서 ID가 섞이기 않게 처음부터 잘 설정해주는 것이 좋다.

배치한 edit control을 우클릭하여 속성을 보면 ID가 나와있고, 수정할 수 있다.

(ID control 이름넘버 순으로 생성이 되는데, 리소스는 우리의 실력이 더 좋아지면 건드리도록 하고 지금은 만지지 말자!)


4. edit control을 총 세개 만들어 배치하고, 아이디를 각각

IDC_MY_EDIT

IDC_TEST_EDIT

IDC_RESULT_EDIT

로 수정해준다.


5. 같은 방법으로 button을 하나 만들어 ID를 IDC_SUM_BTN 으로 수정해준다.

그 후 속성의 캡션부분에 '합산'을 적어준다.


6. 대화상자를 클릭하고 오른쪽 마우스버튼을 눌러 속성으로 들어간다.

글꼴을 기본 MS Shell Dlg(9)에서 ...(더보기)를 클릭해 "굴림, 보통, 9"로 바꾸어준다. 


참고로 @가 붙은 것은 세로폰트이고, '체'가 붙은 것은 자간이 일정한것이다. 통계적인 프로그램을 쓸 때는 굴림'체'를 쓰는 것이 좋다.


여기까지의 화면이다.



7. 만든 합산버튼 더블클릭하면 함수가 자동으로 호출된다.


8. 이제 대화상자에 있는 edit control 에서 정수값 정보를 얻을 것이다.

대화상자 속 모든 컨트롤은 아이템이라고 부른다. 따라서 함수 이름은 GetDlgItemInt.


void CTestControlDlg::OnBnClickedSumBtn()

{

int num1 = GetDlgItemInt(IDC_MY_EDIT);

int num2 = GetDlgItemInt(IDC_TEST_EDIT);

SetDlgItemInt(IDC_RESULT_EDIT, num1 + num2);

}


여기까지 하게되면 소수를 써도 버림으로 정수로 받아서 계산하게 된다. 

실수를 받기 위해서는 함수에 Int대신 Text를 사용한다.


즉, GetDlgItemText를 이용해 예를 들어 2.1이라는 입력된 숫자를 "2.1"이라는 문자열로 인식해서 받아온다.


MFC에서는 CString이라는 class가 제공된다. 문자열을 다루는 class로 문자열을 알아서 받아서 동적할당해준다.

연산자 재정의를 통해서 문자열과 문자열을 덧셈하듯이 합칠 수도 있다.


9. 앞의 설명처럼, GetDlgItemText를 이용하여 코드를 수정해준다.


void CTestControlDlg::OnBnClickedSumBtn()

{

CString str1, str2;


GetDlgItemText(IDC_MY_EDIT, str1);

GetDlgItemText(IDC_TEST_EDIT, str2);

SetDlgItemText(IDC_RESULT_EDIT, str1 + str2);

}

하지만 여기서 이렇게 변경해주면.... 2.1+ 3.4 의 결과값이 5.5가 아닌 "2.13.4"로 뜨게 된다. 여기서 우리는 문자열의 덧셈이 문자열과 문자열을 연결하는 것으로 제공됨을 알 수 있다.


10. 그렇다면 문자열로 받았던 입력값을 실수로 바꾸어주자.


옛날에는 atof( : 아스키 to 플루트), atoi( : 아스키 to 인티져)를 사용했는데 ms에서 유니코드로 바뀌면서 같이 변경되었다. 이 부분은 F1을 눌러 도움말을 참조하여 사용해보자.


double num1 = _wtof(str1);

double num2 = _wtof(str2);


11. 이제 둘을 더하고, 그 결과를 다시 문자열로 바꿔주어 SetDlgItemText함수를 사용할 수 있도록 한다.


result_str.Format(L"%f", num1 + num2);


즉, num1 + num2 실수로 처리된 결과를 Format함수를 이용해서 문자열로 들어가게 한다.


12. 최종적으로 함수는 아래와 같이 작성된다.


void CTestControlDlg::OnBnClickedSumBtn()

{

CString str1, str2, result_str;


GetDlgItemText(IDC_MY_EDIT, str1);

GetDlgItemText(IDC_TEST_EDIT, str2);

double num1 = _wtof(str1);

double num2 = _wtof(str2);

result_str.Format(L"%f", num1 + num2);



SetDlgItemText(IDC_RESULT_EDIT, result_str);

}


13. 실행해보면 결과에 소수점 6째자리까지 모두 나오게 된다. 

만약 이것을 그냥 %.2f로 해결하려 하면 반올림이 일어나버려 결과값에 오차가 생긴다.


여기서 가장 좋은 방법은 뒤에 0이 붙는 소수점 자리만 없애는 것이다.

result_str.TrimRight(); 함수를 사용해보자.


'0'으로 문자를 표시하면 오른쪽부터 0을 제거해가고 다른 것이 나오면 끝나는 함수이다. 여기서 생기는 문제는 11.0000000이 결과일 경우 출력은 11.으로 된다는 것이다.

CString class 도움말을 살펴보면 Right()라는 함수가 있다. 이는 오른쪽부터 ()안의 수만큼의 문자를 받아오는 것이다. 이를 이용해


if(result_str.Right(1)==L".")

result_str = result_str + L"0";


를 추가해주면 마지막에 .으로 끝났을 경우 뒤에 0을 하나 더 붙여준다! 물론 도움말에서 '.'을 제거하는 함수를 찾아서 써도 된다.


-------------------------------------------------------------------------


14. 계산기처럼 버튼을 클릭하면 edit control에 입력이 되도록 해보자.


15. 2,3,4,5 버튼을 만들어 캡션을 수정해주고 더블클릭하여 함수를 등록해준다.


16. 2번버튼 함수에

SetDlgItemInt(IDC_RESULT_EDIT, 2);

를 추가해주는데, 이렇게만 하게 되면 2를 아무리 여러번 눌러도 2만 나오게 된다.


17. 이를 해결하기 위해 아래와 같이 코드를 작성해줄 수 있다.


void CTestControlDlg::OnBnClickedButton2()

{

int num = GetDlgItemInt(IDC_RESULT_EDIT);

num = num * 10 + 2;

SetDlgItemInt(IDC_RESULT_EDIT, num);

}


원래 있던 값에 10을 곱해 2를 더하는 것이므로 우리가 원하는 결과가 입력되는 것을 확인할 수 있다.





대화상자에서 버튼더블클릭을 잘못하여 함수를 잘못 만들었을 때 지우는 방법을 알아보자.


1. 프로젝트명Dlg.h에서 

public : 

afx_msg void OnBnClickedButton5();

를 먼저 삭제한다.


참고로 앞에 afx_msg 는  지워도 상관이 없는데 //{{ 라는 주석이 달려있는 것은 클래스마법사가 참조하기 위해 달아둔 것이므로 지우면 안된다.


2. 프로젝트명Dlg.cpp에서 아래부분을 찾아,

BEGIN_MESSAGE_MAP(CTestControlDlg, CDialogEx)

ON_BN_CLICKED(IDC_BUTTON2, &CTestControlDlg::OnBnClickedButton2) // 이 버튼을 클릭했을 때 저 함수를 부른다.

부모에게 메세지를 전달할 때는 notify라고 말하고 그게 아닐 때는 메세지라고 한다.


참고로 ON_MESSAGE(WM_PAINT,OnPaint) 이렇게 적어야 하는 것인데 약식으로 ON_WM_PAINT() 라고 적는 것이다.


ON_BN_CLICKED(IDC_BUTTON5, &CTestControlDlg::OnBnClickedButton5)  <- 이 줄을 삭제한다.

//notify가 발생하고 (어디에 의해서 발생하고, 어떤 행위를 하겠다) 라는 의미의 줄임이다.



과거에는 새로운 멤버함수를 추가하면 헤더파일도 같이 추가해주어야 했지만, VS2015부터는 멤버함수를 추가하면 앞에 전구모양이 뜨고 그걸 누르면 헤더파일에 추가할 것인지 물어본다! 반대로 헤더파일에 멤버함수를 추가하면 소스파일에 추가할 것이냐는 전구가 뜬다.





+ 과제 : 계산기 만들기


내 방식대로 간단하게 만들어 보았다. 

(이 다음시간을 빠지게 되어 새싹님께 수정을 부탁드릴 수 없었다... 앞으로 혼자 더 공부해야할 듯 하다.)









'TIPS > MFC' 카테고리의 다른 글

[TIPS} 15th 20160825  (0) 2016.08.28
[TIPS] 13th 20160818 (list box / socket)  (0) 2016.08.20
[TIPS] 10th 20160804  (0) 2016.08.20