* WM_COMMAND 메세지의 3가지 처리.
- 메뉴
- 단축키
- Child 윈도우
WM_COMMAND 메세지를 받는기능은 CCmdTarget에 구현되어있다.
CCmdTarget은 AFX클래스의 조상이다. 그러므로 밑의 AFX클래스 넘들은 이넘의 기능을 쓸수있다.
* WM_COMMAND 메세지 전달 순서.
CView 파생 클래스 -> CDocument 파생 -> CFrameWnd 파생 -> CWinApp 파생
* 커맨드 메세지핸들러 함수
커맨드 메세지 핸들러 함수는 일반 메세지핸들러 함수를 오버라이딩 하는것과는 약간 틀리다.
클래스위자드에서 해당 클래스를 선택한다음 Object IDs 의 커맨드ID 를 선택해주면된다.
커맨드 ID는 메뉴나 기타등등의 ID 값이다. 선택한다음 우측의 COMMAND 를 추가 시키면된다.
오늘은 렉트를 하나 그리고 메뉴를 이용하여 색깔을 바꾸는 프로그램이다.
멤버변수로 COLORREF 값을 갖고있고 메뉴를 선택하면 값이 바뀐다음. 뷰에서 그려준다.
* UPDATE_COMMAND_UI
메뉴를 선택하였을때 항목왼쪽에 체크 등을 표시하도록 한다.
- 작성법
클래스위자드를 켜고 다시한번 커맨드 ID를 선택하고 우측의 UPDATE_COMMAND_UI 를
추가시켜 함수를 만든다. 그럼 그 메뉴를 선택하면 이 함수도 실행될것이니라.
인자로는 pCmdUI 로 CmdUI의 주소이다.
ID 값을 멤버변수로 갖고 있다가 메뉴를 선택하면 ID를 비교 같으면 체크표시..
void CMenuTestView::OnUpdateShapeRed(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(m_ShapeID == pCmdUI->m_nID);
}
그런데 이렇게 빨강, 파랑, 초록... 계속 함수를 추가하다보면 함수가 많아지고
소스가 지저분해진다. 연속된 ID이면 한번에 처리할 수 있다.
우선 메뉴의 View -> ResourceSymbols 에 보면 메뉴의 ID 값을 볼 수 있다.
하나로 묶을 커맨드 들이 순서대로 있는지 확인을 한다.
* ON_COMMAND_RANGE 및 ON_UPDATE_COMMAND_UI_RANGE
ON_COMMAND_RANGE ( 몇번부터,몇번까지,여기함수실행);
그러므로 1번째는 2번째 ID 값보다 작은값이 와야한다.
추가하는 방법은 함수본체가 있는 CPP파일의 맨 위에 보면 메세지 맵의 //}}AFX_MSG_MAP
주석처리 된부분 바로 밑에 다 추가한다. 주석처리 된부분 안에 넣으면 클래스 위자드가
컴파일 할때 지가 작성한것이 아니라고 다 지워버린다. 성깔있는 넘이다.
예제)
BEGIN_MESSAGE_MAP(CMenuTestView, CView)
//{{AFX_MSG_MAP(CMenuTestView)
ON_WM_CONTEXTMENU()
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(IDC_SHAPE_RED,IDC_WHITE,OnShapeColor) <= 요기
ON_UPDATE_COMMAND_UI_RANGE(IDC_SHAPE_RED,IDC_WHITE,OnUpdateShapeColor)
END_MESSAGE_MAP()
또한 헤더파일의 밑에 쯤에.. 여기도 마찬가지 DECLARE_MESSAGE_MAP() 바로위에..
//{{AFX_MSG(CMenuTestView)
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
//}}AFX_MSG
afx_msg void OnShapeColor(UINT nID); <= 요기
afx_msg void OnUpdateShapeColor(CCmdUI *pCmdUI);
DECLARE_MESSAGE_MAP() <= 요기 위로추가
};
이렇게 작성을 하고 함수 본체를 만들면된다.
ON_COMMAND_RANGE 는 ID 값이 넘어오고
ON_UPDATE_COMMAND_UI_RANGE 는 CmnUI 의 주소가 넘어온다(pCmdUI)
* 팝업메뉴... TrackPopMenu
마우스 오른쪽 버튼..
void CMenuTestView::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMenu *pMenu = GetParentFrame()->GetMenu(); // 프레임을 참조한다.!!
CMenu *pSubMenu = pMenu->GetSubMenu(4);
// 0 1 2 3 4 서브메뉴가 4번째 있으므로
ClientToScreen(&point); // 알버튼은 클라이언트 좌표로 기억한다 그러므로 화면좌표로 변경
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x,point.y,this,
NULL);
CView::OnRButtonDown(nFlags, point);
}
void CMenuTestView::OnContextMenu(CWnd* pWnd, CPoint point)
{
// TODO: Add your message handler code here
CMenu *pMenu = GetParentFrame()->GetMenu();
CMenu *pSubMenu = pMenu->GetSubMenu(4);
//ClientToScreen(&point); //이넘은 기본적으로 스크린좌표(화면좌표)를 갖고있다.
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN |TPM_RIGHTBUTTON,point.x,point.y,pWnd,
NULL);
}
* RbuttonDown 과 ContextMenu 의 다른점은 어디좌표를 갖고있느냐이다. 그것만 다르다.
* 컴포넌트 개념..
사실 이렇게 작성하지 않아도 메뉴의 프로젝트의 Add Project 에 Components and control..
에 보면 팝업메뉴 컴포넌트가 있다. 이것만 에드 시키면 따로 노가다를 할 필요가 없어진다.
또하나로 Splash Screen 컴포넌트는 프로그램시작시 처음에 화면이 다 뜨기전에 그림을
보여주는 기능.. VC60 도 실행시키면 첨에 로고비스꾸리한게 보인다. 그게 그거다.
암튼 컴포넌트만 맹글어서 팔아먹는 사람들도 있다한다.
* 툴바
리소스뷰의 툴바를 선택하고 회색으로 된 네모를 선택하면 추가가 된다 거기다 그림을
그릴수도 있고 두번눌르면 메뉴의 커멘드 ID를 연결할수도 있다. 그래서 그 아이콘을 선택하면
메뉴의 같은 ID가 실행이 된다. 밑의 Prompt 는 프로그램 실행하면 하단의 상태바에
설명을 달아준다. 그리고 만약 "\n빨강" 이라고 덧붙여주면 풍선도움말에 "빨강" 이라고 나온다.
툴바와 메뉴 의 ID 값만 맞춰주면 한쪽에서 수정해도 같이 변경이된다
[출처] [2. 17] MFC 4일차.. 메뉴 관련..|작성자 교