1. 程式人生 > >如何在MFC中自定義訊息

如何在MFC中自定義訊息

訊息對映、迴圈機制是Windows程式執行的基本方式。VC++   MFC   中有許多現成的訊息控制代碼,可當我們需要完成其它的任務,需要自定義訊息,就遇到了一些困難。在MFC   ClassWizard中不允許新增使用者自定義訊息,所以我們必須在程式中新增相應程式碼,以便可以象處理其它訊息一樣處理自定義訊息。通常的做法是採取以下步驟:  
   
    第一步:定義訊息。  
   
    推薦使用者自定義訊息至少是WM_USER+100,因為很多新控制元件也要使用WM_USER訊息。  
   
  #define   WM_MY_MESSAGE   (WM_USER+100)      
   
    第二步:實現訊息處理函式。該函式使用WPRAM和LPARAM引數並返回LPESULT。    
   
  LPESULT   CMainFrame::OnMyMessage(WPARAM   wParam,   LPARAM   lParam)    
  {    
  //   TODO:   處理使用者自定義訊息    
  ...    
  return   0;    
  }      
   
    第三步:在類標頭檔案的AFX_MSG塊中說明訊息處理函式:  
   
  class   CMainFrame:public   CMDIFrameWnd    
  {    
  ...    
  //   一般訊息對映函式    
  protected:    
  //   {{AFX_MSG(CMainFrame)    
  afx_msg   int   OnCreate(LPCREATESTRUCT   lpCreateStruct);    
  afx_msg   void   OnTimer(UINT   nIDEvent);    
  afx_msg   LRESULT   OnMyMessage(WPARAM   wParam,   LPARAM   lParam);    
  //}}AFX_MSG    
  DECLARE_MESSAGE_MAP()    
  }    
   
    第四步:在使用者類的訊息塊中,使用ON_MESSAGE巨集指令將訊息對映到訊息處理函式中。    
   
  BEGIN_MESSAGE_MAP(CMainFrame,   CMDIFrameWnd)    
  //{{AFX_MSG_MAP(CMainFrame)    
  ON_WM_CREATE()    
  ON_WM_TIMER()    
  ON_MESSAGE(WM_MY_MESSAGE,   OnMyMessage)    
  //}}AFX_MSG_MAP    
  END_MESSAGE_MAP()    
  如果使用者需要一個定義整個系統唯一的訊息,可以呼叫SDK函式RegisterWindowMessage定義訊息:  
   
  static   UINT   WM_MY_MESSAGE=RegisterWindowMessage("User");    
   
    並使用ON_REGISTERED_MESSAGE巨集指令取代ON_MESSAGE巨集指令,其餘步驟同上。  
   
    當需要使用自定義訊息時,可以在相應類中的函式中呼叫函式PostMessage或SendMessage傳送訊息PoseMessage(WM_MY_MESSAGE,O,O);   如果向其他程序傳送訊息可通過如下方法傳送訊息:  
   
  DWORD   result;  
  SendMessageTimeout(wnd->m_hWnd,   //   目標視窗  
  WM_MY_MESSAGE,   //   訊息  
  0,   //   WPARAM  
  0,   //   LPARAM  
  SMTO_ABORTIFHUNG   |  
  SMTO_NORMAL,  
  TIMEOUT_INTERVAL,  
  &result);    
  以避免其它程序如果被阻塞而造成系統死等狀態。  
   
    可是如果需要向其它類(如主框架、子視窗、視類、對話方塊、狀態條、工具條或其他控制元件等)傳送訊息時,上述方法顯得無能為力,而在程式設計過程中往往需要獲取其它類中的某個識別訊號,MFC框架給我們造成了種種限制,但是可以通過獲取某個類的指標而向這個類傳送訊息,而自定義訊息的各種動作則在這個類中定義,這樣就可以自由自在的向其它類傳送訊息了。  
   
    下面舉的例子敘述了向視類和框架類傳送訊息的方法:  
   
    在主框架類中向視類傳送訊息:  
   
    視類中定義訊息:  
   
  ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)   //定義訊息對映  
  視類定義訊息處理函式:  
   
  //   訊息處理函式  
  LRESULT   CMessageView::OnMyMessage(WPARAM   wParam,   LPARAM   lParam)  
  {  
  //   TODO:   處理使用者自定義訊息    
  ...    
  return   0;  
  }    
   
  //傳送訊息的測試函式  
  void   CMainFrame::OnTest()  
  {  
  CView   *   active   =   GetActiveView();//獲取當前視類指標  
  if(active   !=   NULL)  
  active->PostMessage(WM_MY_MESSAGE,0,0);  
  }    
   
    在其它類中向視類傳送訊息:  
   
  //傳送訊息的測試函式  
  void   CMainFrame::OnTest()  
  {  
  CMDIFrameWnd   *pFrame;  
  CMDIChildWnd   *pChild;  
  CView   *pView;  
  //獲取主視窗指標  
  pFrame   =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;  
  //   獲取子視窗指標  
  pChild   =   (CMDIChildWnd   *)   pFrame->GetActiveFrame();  
  //獲取視類指標  
  pView   =   pChild->GetActiveView();  
  if(pView   !=   NULL)  
  pView->PostMessage(WM_MY_MESSAGE,0,0);//傳送訊息  
  }    
   
    其餘步驟同上。  

在視類中向主框架傳送訊息:  
   
    首先在主框架中定義相關的訊息,方法同上,然後在傳送訊息的函式中新增程式碼如下  
   
  //傳送訊息的測試函式  
  void   CMessageView::OnTest()  
  {  
  CFrameWnd   *   active   =   GetActiveFrame();//獲取當前主視窗框架指標  
  if(active   !=   this)  
  active->PostMessage(WM_MY_MESSAGE,0,0);  
  return   0;  
  }    
   
    在其它類中向不同的類傳送訊息可依次方法類推,這樣我們的程式就可以的不受限制向其它類和程序傳送訊息,而避免了種種意想不到的風險。  
   
    下面一個例子程式為多文件程式裡在一對話方塊中向視類傳送訊息,詳述了傳送自定義訊息的具體過程。  
  實現步驟:  
   
    第一步:在VC++中新建工程Message,所有ClassWizard步驟選項均為預設,完成。  
   
    第二步:在主選單中新增測試選單為調出對話方塊,在框架類中建立相應函式OnTest()  
   
    第三步:在資源中建立對話方塊,通過ClassWizard新增新類TestDialog,新增測試按鈕,  
   
    在對話方塊類中建立相應函式OnDialogTest()  
   
  //通過對話方塊按鈕傳送訊息的函式  
  void   TestDialog::OnDialogTest()  
  {  
  CMDIFrameWnd   *pFrame;  
  CMDIChildWnd   *pChild;  
  CView   *pView;  
  //獲取主視窗指標  
  pFrame   =(CMDIFrameWnd*)AfxGetApp()->m_pMainWnd;  
  //   獲取子視窗指標  
  pChild   =   (CMDIChildWnd   *)   pFrame->GetActiveFrame();  
  //獲取視類指標  
  pView   =   pChild->GetActiveView();  
  if(active   !=   NULL)  
  active->PostMessage(WM_MY_MESSAGE,0,0);//傳送訊息  
  }    
   
    在Message.h標頭檔案中新增如下語句:  
   
  static   UINT   WM_MY_MESSAGE=RegisterWindowMessage("Message");    
   
    第四步:在視類中新增自定義訊息:  
   
    在標頭檔案MessageView.h中新增訊息對映  
   
  protected:  
  //{{AFX_MSG(CMessageView)  
  //}}AFX_MSG  
  afx_msg   LRESULT   OnMyMessage(WPARAM   wParam,   LPARAM   lParam);   //此行為新增程式碼  
  DECLARE_MESSAGE_MAP()  
  在視類檔案MessageView.cpp中的訊息對映中新增自定義訊息對映  
  BEGIN_MESSAGE_MAP(CMessageView,   CView)  
  //{{AFX_MSG_MAP(CMessageView)  
  //}}AFX_MSG_MAP  
  //   Standard   printing   commands  
  ON_REGISTERED_MESSAGE(WM_MY_MESSAGE,OnMyMessage)   //此行新增程式碼定義唯一訊息  
  END_MESSAGE_MAP()    
   
    新增相應的0訊息處理函式  
   
  LRESULT   CMessageView::OnMyMessage(WPARAM   wParam,   LPARAM   lParam)  
  {  
  CRect   rect;  
  GetClientRect(&rect);  
  InvalidateRect(&rect);  
  test=!test;  
  return   0;  
  }    
   
    在MessageView.h中添加布爾變數   public:BOOL   test;  
   
    在視類建構函式中初始化   test變數:test=FALSE;  
   
    修改CMessageView::OnDraw()函式  
   
  void   CMessageView::OnDraw(CDC*   pDC)  
  {  
  CMessageDoc*   pDoc   =   GetDocument();  
  ASSERT_VALID(pDoc);  
  //   以下程式顯示訊息響應效果  
  if(test)  
  pDC->TextOut(0,0,"訊息響應!");  
  }    
   
    第五步:顯示測試對話方塊  
   
    在MainFrame類中包含對話方塊標頭檔案:  
   
  #include   "TestDialog.h";  
  OnTest()函式中新增程式碼  
  void   CMainFrame::OnTest()  
  {  
  TestDialog   dialog;  
  dialog.DoModal();  
  }    
   
    執行程式,在測試選單開啟對話方塊,點選測試按鈕即可看到結果