MFC中使用者自訂類響應自訂訊息

來源:互聯網
上載者:User

首先能夠響應訊息的類必須都從CCmdTarget類中派生,因為只有以這個類中提供了訊息的架構和處理機制,而CWnd類也派生與此類。CWinApp類、CDocument類、CDocTemplate類等都是CCmdTarget的衍生類別,即子類;而CFrameWnd類、CView類、CDialog類等都是從CWnd中派生的,其實也是CCmdTarget的子孫,所以都能夠響應訊息,但是響應訊息的種類不太相同。

那麼,如果自己定義的類要求響應命令訊息(就是WM_COMMAND,也就是一些菜單、工具列中的訊息,包括快速鍵,這類訊息處理的機制與其他以WM_開頭的訊息處理機制不同,它具有一條層次明確的訊息流程動路徑),那麼自訂的類可以從CCmdTarget中派生。由於CWnd表單類派生於CCmdTarget父類,那麼從CWnd中派生的類也可以理所應當的響應命令訊息。這種命令訊息無論是往已有的一些諸如CWinApp類中還是自訂的類中添加都是一件非常容易的事情,只需用嚮導即可,在此不再敘述。

如果使用者自訂的類要求響應普通的Windows訊息(也就是以WM_開頭,除了WM_COMMAND以外的訊息,這類訊息在WM_USER以下的是系統訊息,WM_USER以上的可以由使用者自己定義),那就要求自訂的類必須從CWnd中派生。這是由於此類訊息的處理機制決定的,這類訊息沒有命令訊息那條繁瑣的流動路徑,而是訊息發出者直接發給對應CWnd的表單控制代碼,由CWnd負責訊息的響應。所以這類訊息必須同一個CWnd類對應,更精確的說必須與一個HWND類型的表單控制代碼相對應。這樣得出一個重要的結論,就是從CCmdTarget中派生而沒有從CWnd派生的類沒有處理此類訊息的能力。

綜上所述,就是為什麼命令訊息可以放到大部分類中處理,包括CWinThread、CWinApp、CDocument、CView、CFrameWnd或是自訂的類中,而普通Windows訊息和使用者自訂的訊息只能放到CFrameWnd和CView等派生與CWnd中的類中處理。

由此可見,我們自訂的類要想響應自訂訊息就只能從CWnd中派生(當然不響應任何訊息的類可以從CObject中派生)。先來看看如何自訂訊息:

在.h中做的工作:

第一步要聲明訊息:

#define WM_MYMSG WM_USER+8

第二步要在類聲明中聲明訊息映射:

DECLARE_MESSAGE_MAP()

第三步要在類聲明中定義訊息處理函數:

afx_msg LRESULT MyMsgHandler(WPARAM,LPARAM);

在.cpp中做的工作:

第四步要實現訊息映射:

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
ON_MESSAGE(WM_MYMSG,OnMyMsgHandler)
END_MESSAGE_MAP()

第五步要實現訊息處理函數(當然可以不實現):

LRESULT CMainFrame::OnMyMsgHandler(WPARAM w,LPARAM l)
{
AfxMessageBox("Hello,World!");
return 0;
}

在引發或發出訊息的地方只用寫上:

::SendMessge(::AfxGetMainWnd()->m_hWnd,WM_MYMSG,0,0);

到此,自訂訊息完畢,這是好多網上文章都寫的東西。大家會發現上面代碼是在CMainFrame類中實現的,但是如果要用自訂類,就沒有那麼簡單了。顯然把第四步與第五步的CMainFrame換成自訂的類名(這裡我用CMyTestObject來代表自訂類)是不能正常工作的。原因在於在發送訊息的SendMessage函數中的第一個參數是要響應訊息對應的HWND類型的表單控制代碼,而CMyTestObject類中的m_hWnd中在沒有調用CWnd::Create之前是沒有任何意義的,也就是沒有調用CWnd::Create或CWnd::CreateEx函數時,CWnd不對應任何表單,訊息處理不能正常運作。

所以,又一個重要的結論,在自訂類能夠處理任何訊息之前一定要確保m_hWnd關聯到一個表單,即便這個表單是不可見的。那麼有人說,在自訂類的建構函式中調用Create函數就行了,不錯,當然也可以在別處調用,只要確保在訊息發送之前。但是,Create的調用很有說法,要注意兩個地方,第一個參數是類的名稱,我建議最好設為NULL;第五個參數是父表單對象的指標,這個函數指定的對象一定要存在,我建議最好為整個程式的主表單。還有很多人問第六個參數的意義,這個參數關係不大,是子表單ID,用於傳給父表單記錄以便識別。如下是我的自訂類的建構函式:

CMyTestObject::CMyTestObject()
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),::AfxGetMainWnd(),1234);
}    //一定要在產生主表單後使用,在主表單完成OnCreate訊息的處理後

CMyTestObject::CMyTestObject(CWnd *pParent)
{
CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),pParent,1234);
}

不能如下調用Create,因為此時CMyTestObject不關聯任何表單,所以this中的m_hWnd無效:

CWnd::Create(NULL,"MyTestObject",WS_CHILD,CRect(0,0,0,0),this,1234);

這時上面四、五兩步修改成:

BEGIN_MESSAGE_MAP(CMyTestObject, CWnd)
ON_MESSAGE(WM_MYMSG,OnMyMsgHandler)
END_MESSAGE_MAP()

LRESULT CMyTestObject::OnMyMsgHandler(WPARAM w,LPARAM l)
{
AfxMessageBox("My Messge Handler in My Self-Custom Class!");
return 0;
}

在類外部發出訊息:

CMyTestObject *test=new CMyTestObject();
::SendMessage(test->m_hWnd,WM_MYMSG,0,0);

在類內部某個成員函數(方法)中發出訊息:

::SendMessage(m_hWnd,WM_MYMSG,0,0);

最後一個問題便是容易產生警告錯誤的表單回收,自訂的類要顯式調用表單銷毀,解構函式如下:

CMyTestObject::~CMyTestObject()
{
CWnd::DestroyWindow();
}

本文來自CSDN部落格,轉載請標明出處:http://blog.csdn.net/yuwei19840916/archive/2008/12/04/3445659.aspx

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.