Computer(IT)/Visual Studio C++

MFC메뉴 처리

약탄치킨 2008. 12. 1. 04:03
반응형

* WM_COMMAND  메세지의 3가지 처리.

   - 메뉴

   - 단축키

   - Child 윈도우

 

WM_COMMAND 메세지를 받는기능은 CCmdTarget에 구현되어있다.

CCmdTargetAFX클래스의 조상이다. 그러므로 밑의 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 값만 맞춰주면 한쪽에서 수정해도 같이 변경이된다

반응형