주요 개념
1. Sub Classing
2. Thread
3. Counting & Delay
목표
-Button을 꾹~ 누르는 동안 Edit Control의 숫자를 자동으로 상승시키기.
-일반적인 Button Counting도 함께 합니다.
--------------------------------------------------------------
일단 따라해 봅시다.
1. 일반적인 Button Counting
1.MFC 새 프로젝트를 만듭니다. 프로젝트명은 MFCButtonCounting라고 하겠습니다.
2.아래와 같이 오브젝트를 배치합니다.
Edit Control ID : IDC_EDIT1, IDC_EDIT2
Button ID : IDC_BUTTON1, IDC_BUTTON2
누르는 동안의 Counting에 사용할 버튼과 Edit는 상단의 IDC_BUTTON1과 IDC_EDIT1 입니다.
2는 그냥 버튼 Counting에 사용하겠습니다.
MFCButtonCountingDlg.h에 public으로 int EDText1변수를 만들었습니다.
Dialog 리소스에서 해당 오브젝트에 우클릭 후 변수추가를 해주면 됩니다.
일단 평범한 버튼카운터를 만들어 봅시다. 잘 아시는 분은 넘어가셔도 좋습니다.
Button2의 속성의 컨트롤 이벤트에서 BN_CLICKED를 활성화 해 주었습니다.
우리는 생성된 OnBnClickedButton2를 Overriding해주면 됩니다.
public영역에서 2개의 변수와 하나의 함수를 발견할 수 있습니다. cpp로 가서 OnBnClickedButton2()를 아래와 같이 작성해 줍시다.
EDText2+=1;
UpdateData(FALSE);
실행시키시면 버튼2를 누를때마다 숫자가 증가함을 확인할 수 있습니다.
2. 지속되는 Button Counting
위와같이 일반적인 카운터은 쉽게 만들 수 있으나 버튼을 누르는 동안 지속되는 카운터는 몇가지 고려해야 할 사항이 있습니다.
첫째로 MFC에서는 누르는동안 실행해주기 위한 함수는 제공하지 않습니다.
둘째로 버튼을 누르고 카운팅하는 동안 다른 동작이 정지해서는 안됩니다.
두번째 문제는 Thread를 사용해서 쉽게 해결할 수 있습니다.
첫번째 때문에 저희가 이를 위한 함수를 만들어야 하는거죠.
이를 위한 해결책을 두가지 제시할 수 있는데 첫째가 PreTranslateMessage이고 둘째가 Sub Classing입니다.
PreTranslateMessage를 통해 우리는 소프트웨어에서 발생하는 모든 메시지를 가로채서 이에 대한 처리를 할 수 있습니다.
SubClassing을 사용하면 만들기는 조금 귀찮아질 수 있으나 원하는 메시지에 대해서만 처리시킬 수 있습니다. 여기서는 SubClassing을 사용합니다.
SubClassing을 사용해서 Button1에 대해 종속되는 Class를 하나 생성할 것입니다.
1.
프로젝트->클래스 추가를 통해 MFC클래스를 만들어 줍니다.
위와 같이 만들어 줍니다.
2.
클래스마법사를 이용해서 다음과 같이 메시지 함수를 오버라이딩 합니다.
버튼을 눌렀을때와 뗐을때의 메시지를 만들었습니다.
3.
'GetParent()->'로 부모클래스의 객체를 불러오고
PostMessageW를 사용해서 부모 클래스에 메시지를 보냅니다. GetDlgCtrlID()를 통해 부모객체 여기서는 BUTTON1의 아이디 IDC_BUTTON1을 참조할 수 있습니다. 여기서 +몇을 해 주어도 상관 없습니다.
후에 부모클래스에서 OnCommand를 통해 받는 파라메터값이 됩니다.
Dlg의 헤더에 아래 변수를 추가합니다.
private:
ButtonClass m_TestButton;
m_TestButton : 앞서 작성한 클래스형의 변수입니다.
아래와 같이 초기화를 해줍니다.
이렇게 m_TestButton은 IDC_BUTTON1의 서브클래스가 되었습니다.
이걸로 서브클래스에서 작성할 것은 끝났습니다.
4.
이제 Thread를 만듭니다.
Dlg 헤더파일에 다음을 추가로 작성해 줍시다.
public:
CWinThread* CountingThread;
LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);
private:
ButtonClass m_TestButton;
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
CountingThread : Thread 포인터 변수입니다.
OnCommand : 클래스가 메시지를 받았을 때의 동작을 정하는 함수입니다.
OnUpdateData : 메시지 처리후의 동작입니다. 짧지만 제일 중요한 부분입니다.
OnCommand는 클래스마법사에서 가상함수로 만들 수 있습니다.
OnUpdateData는 직접 작성하시면 됩니다.
위와 같은 함수를 만들어 줍시다.
Delay는 말 그대로 버튼을 누르고 있는동안 딜레이를 주기위한 함수입니다. 이부분은 가져온 부분이라서 관심있으신 분은 스스로 찾아보셔야 하겠습니다.
MyThread는 버튼을 누른동안 Thread로써 기능할 함수입니다. 여기서 pClass는 Dlg클래스가 되겠습니다. 저 두 함수위에 bool threadFlag = false로 변수를 하나 만들어 주었습니다. 버튼을 누른동안 true가 될것이고 떼었을 때 false로 전환될것입니다. 딜레이를 주면서 매 루프마다 변수를 1씩 늘려줍니다.
여기서 PostMessageW는 잠시 보류하고 대신 UpdateData(FALSE); 구문을 넣어줍시다.
그 아래 PostMessageW(THREAD_UPDATE)가 중요합니다.
주의할 것은 두 함수 다 클래스 밖에 있는 전역함수라는 것입니다.Thread는 클래스 밖에서 동작하고 있습니다.
5.
Thread를 동작시켜 봅시다.
OnCommand의 내용입니다. DestroyThread는 아직 놔둡시다. 다른 파일로 해서 클래스명이 약간 다릅니다. 조심해 주세요.
서브클래스로부터 받은 값에 따라 동작하게 하였습니다.
여기서 중요한 구문은 CountingThread = AfxBeginThread(MyThread,this) 입니다.
AfxBeginThread에 대해서 조사바랍니다. MFC에서 사용하는 Thread관련 함수이며 대상 함수가 정적함수여야 인수로 받을 수 있습니다.
만들어진 소프트를 실행시켜 봅시다. 에러가 발생합니다. UpdateData함수는 메인 클래스 밖의 함수에서 사용할 수 없습니다. 우선은 MyThread의 UpdateData구문을 지워줍시다. 그러면 값의 갱신이 실시간으로는 보이지 않지만 갱신되고 있음을 알 수 있습니다.
꾹~ 누르는 동안은 아무변화 없다가 버튼을 떼면 값이 갱신됩니다.
6.
클래스 밖에서 UpdateData구문을 실행할 수 없기 때문에 메시지를 보내 실행하게 해야 합니다.
Dlg의 헤더파일에 아래와 같은 구문을 넣습니다.
클래스 내에 아래 구문을 추가합니다.
public:
LRESULT OnUpdateData(WPARAM wParam, LPARAM lParam);
OnUpdateData : 메시지 처리후의 동작입니다. 짧지만 제일 중요한 부분입니다.
OnUpdateData는 직접 작성하시면 됩니다.
Dlg의 cpp의 메시지맵에 ON_MESSAGE구문을 넣습니다.
Dlg의 cpp에 아래 함수를 추가합니다.
위 MyThread 함수에 있는 PostMessageW 를 활성화 시킵시다.
실시간으로 업데이트되는 것을 확인할 수 있습니다.
'Software > Programming' 카테고리의 다른 글
volatile(C,C++) (0) | 2016.04.15 |
---|---|
구조체와 공용체. 공용체의 패딩 (0) | 2015.01.11 |
비트필드(Bit Field) (0) | 2014.08.11 |
[비선형 자료구조]트리.그래프 (AVL 트리) (1) | 2013.05.25 |
전위표기. 후위표기 (0) | 2013.05.25 |