1. 程式人生 > >在MFC中新增使用者自定義訊息

在MFC中新增使用者自定義訊息

首先弄清楚兩點:

(1)誰要傳送這個訊息(2)誰要接受這個訊息。  

用一個簡單的例子來說明。物件A向B(也可以就是A到A)傳送訊息。  

1 傳送訊息  

首先在A的標頭檔案中定義這個訊息:  

  #define WM_USERMESSAGE WM_USER+30  

   所有自定義訊息都是以WM_USER訊息為基礎加上一個任意的自然數來表示的。A是向外傳送訊息的物件,因此在A的某個方法(函式)裡就會呼叫用來發消 息的函式B::SendMessage()/B::PostMessage(),因為是B接受訊息,因此是如上的形式。  

2 接受訊息  

  物件接受一個訊息,應該有三部分:在標頭檔案中有該訊息的處理函式的原型;在實現檔案中有接受訊息對映的巨集; 以及該訊息的處理函式的具體實現。  

2.1 標頭檔案中加上自定義訊息的處理函式原型  

  在DECLARE_MESSAGE_MAP()語句之前,一對AFX_MSG之間加上如下形式的函式原型:

  afx_msg LRESULT OnProcName( WPARAM wParam, LPARAM lParam );  

  對Win32來說,wParam, lParam是傳遞訊息最常用的手段。  

2.2 在實現檔案中加上接受訊息對映的巨集  

  在cpp檔案裡,BEGIN_MESSAGE_MAP語句之後,在一對AFX_MSG_MAP之間,增加 如下形式的程式碼: 

  ON_MESSAGE(WM_USERMESSAGE, OnProcName)  

上面是不用分號結尾的。
  

2.3 在實現檔案中給出訊息處理函式的具體實現。



發信人: Amia (小羊·橘子·和中南海有緣), 信區: VisualC
標  題: MFC中自由使用自定義訊息
發信站: 哈工大紫丁香 (2003年11月26日07:45:34 星期三), 站內信件
 
訊息對映、迴圈機制是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或SendMessa
ge傳送訊息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();
}  
 
  執行程式,在測試選單開啟對話方塊,點選測試按鈕即可看到結果。