窗口消息的传递

来源:互联网 发布:韩剧tv mac靠谱吗 编辑:程序博客网 时间:2024/06/02 23:43
声明:本文非本人所写,本文已经写在本人CSDN博客里。本原来源于一篇英文文章的翻译。

        消息(Message)是窗口间通信的最重要的方式之一。传统的程序从main()函数处开始一行一行的执行直到退出,但是窗口的概念则不同。窗口对事件(event)进行响应,这种事件称为消息。事件由程序本身、其他程序或系统程序产生,这些事件又产生消息。鼠标移动、按键等都会产生事件。消息分为两种即窗口消息和线程消息。这里只分析窗口消息。

         所谓的窗口消息,大致上,必须传递给一个窗口。所有的消息都存储在消息队列(Message Queue)中。消息队列用于在应用程序之间传递消息。

        从消息队列中捕获消息的方式是消息循环(Message Loop)。一旦一个消息被某个窗口接受,消息循环即分配此消息并调用一个消息句柄,有一个由程序员设计的函数用于处理此消息。

        消息循环在接收到WM_QUIT消息后终止,并指示程序结束。当用户选择File菜单下的Exit子菜单、点击关闭按钮、按下alt+F4时均会产生WM_QUIT消息。窗口有缺省的消息句柄用来进行缺省行为。例如,按钮(Button)派生于窗口类,当按钮接收到WM_PAINT时会重新绘制按钮,当左击按钮时会接收到WM_LBUTTONDOWN并自绘按下的按钮形态。

        窗口定义了很多类型的消息,他们通常以“WM”开头。例如WM_SIZE,当窗口大小发生变化时发送此消息。在MFC中,用On代替“WM_”,例如WM_SIZE在MFC中表示为OnSize。

        一个消息有两个参数,这两个参数携带该事件的一些信息。每个参数均是32位宽的,lParam和wParam。有的时候消息也会返回一个值给发送该消息的窗口。

        MFC自动的生成了消息循环所需的代码,WinMain调用的CWinApp成员函数提供消息循环并将这些消息送给各个窗口。需要我们做的只是创建消息句柄,这可以借助于ClassWizard完成。下面即是一个响应WN_CLOSE消息的例子。
程序代码:
view plaincopy to clipboardprint?void CAboutWindow::OnClose() 

    int Ret = MessageBox(_T("Are you sure you want to close the window?"), 
                         _T("Close Window?"), MB_YESNO); 
    if(Ret == IDYES){ 
        // The User is sure, close the window by calling the base class 
        
// member 
        CWnd::OnClose() 
    } 
    else
        // The user pressed no, screen out the message by not calling 
        
// the base class member 

        
//Do nothing 
    } 

void CAboutWindow::OnClose()
{
    int Ret = MessageBox(_T("Are you sure you want to close the window?"),
                         _T("Close Window?"), MB_YESNO);
    if(Ret == IDYES){
        // The User is sure, close the window by calling the base class
        
// member
        CWnd::OnClose()
    }
    else{
        // The user pressed no, screen out the message by not calling
        
// the base class member

        
//Do nothing
    }
}
        为了窗口间的通信,程序员需要自己发送消息。由于消息均是窗口发送的,所以需要一个C++窗口指针。可以通过CWnd::FindWindow、GetDlgItem()、GetParent()等获得窗口指针。CWnd类有一个SendMessage()成员函数用于发送消息给他的窗口。例如,如果有一个日历控件需要去关闭,可以通过产生一个WM_CLOSE消息去告知该控件。可以通过CWnd::FindWindow()传递一个Caption来获得指向该控件的C++窗口指针。
程序代码:
view plaincopy to clipboardprint?CWnd *pCalc; 
//Get a pointer to the "Calculator" Window 
pCalc = CWnd::FindWindow(NULL, _T("Calculator)); 
if(pCalc == NULL){ 
    //Couldn't find Calculator 

else
    pCalc->SendMessage(WM_CLOSE); 
    //Presto! The Calculator should close. 

当一个窗口接收到某个消息后,MFC将调用类的成员函数。但是MFC如何知道该调用哪个函数呢?

        为了解决上述问题,MFC运用了一个叫做消息映射(Message Map)机制。消息映射就是将消息和所要调用的函数绑定在一起。一旦接受到一个消息,MFC将进入消息映射去寻找与该消息相对应的消息句柄。

         MFC采用的是一系列的宏(Macros)去添加消息映射到类中。当运用ClassWizard去添加一个消息句柄时首先添加该 函数到类中然后添加响应的宏到消息映射中。例如若用ClassWizard添加WM_CLOSE的消息句柄时,会有一下三个动作:

1.在类的实现(.cpp)中的消息映射中:

程序代码:
view plaincopy to clipboardprint?BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) 
    //{{AFX_MSG_MAP(CAboutDlg)  
    ON_WM_CLOSE() 
    //}}AFX_MSG_MAP  
END_MESSAGE_MAP() 
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    ON_WM_CLOSE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()
2.在类(.h)声明中声明函数:该函数前有afx_msg关键字

程序代码:
view plaincopy to clipboardprint?protected
    //{{AFX_MSG(CAboutDlg)  
    afx_msg void OnClose(); 
    //}}AFX_MSG  
    DECLARE_MESSAGE_MAP() 
protected:
    //{{AFX_MSG(CAboutDlg)
    afx_msg void OnClose();
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
3.在类的实现(.cpp)中:

程序代码:
view plaincopy to clipboardprint?void CAboutDlg::OnClose()  

    // TODO: Add your message handler code here and/or call default  
     
    CDialog::OnClose(); 

void CAboutDlg::OnClose()
{
    // TODO: Add your message handler code here and/or call default
   
    CDialog::OnClose();
}

宏DECLARE_MESSAGE_MAP()告知MFC给消息映射添加必要的代码。

宏BEGIN_MESSAGE_MAP()表示消息映射的开始,括弧类的两个参数指示了发送消息的类和其基类。

宏END_MESSAGE_MAP()表示消息映射的结束。

        有一些消息ClassWizard并不支持但是可以手工添加。但有得时候没有消息映射宏,这个时候可以采用通用宏ON_MESSAGE,利用该宏可以传递任何消息。

程序代码:
view plaincopy to clipboardprint?afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam); 
afx_msg LRESULT OnMessage(WPARAM wParam, LPARAM lParam);

         OnMessage()是句柄函数,ON_MESSAGE有两个参数,句柄的地址和消息。例如下面的例子将WM_GETTEXTLENGTH映射到OnGetTextLength():

程序代码:
view plaincopy to clipboardprint?ON_MESSAGE (WM_GETTEXTLENGTH, OnGetTextLength) 
ON_MESSAGE (WM_GETTEXTLENGTH, OnGetTextLength)
OnGetTextLength的原形为:

view plaincopy to clipboardprint?afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam); 
afx_msg LRESULT OnGetTextLength(WPARAM wParam, LPARAM lParam);

         有得时候,需要在两个窗口或两个应用程序间进行通信,一个简单的解决方法是采用自定义消息。为了避免与系统定义的消息冲突,需要运用一个大于0xBFF的数WM_APP。

程序代码:
view plaincopy to clipboardprint?#define WM_DELETEALL WM_APP + 0x100  
//...  
pYourDialog->SendMessage(WM_DELETEALL, 00); 
#define WM_DELETEALL WM_APP + 0x100
//...
pYourDialog->SendMessage(WM_DELETEALL, 00); 

        运用宏WM_MESSAGE完成消息映射,将WM_DELETEALL与句柄函数OnDeleteAll()绑定。

程序代码:
view plaincopy to clipboardprint?#define WM_DELETEALL WM_APP + 0x100  
//...  
//Message Map entry:  
ON_MESSAGE (WM_DELETEALL, OnDeleteAll) 
//OnDeleteAll is prototyped as   
afx_msg LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam); 
//And is implemented as   
LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam){ 
    //Do What ever you want  
    return somevalue; 

#define WM_DELETEALL WM_APP + 0x100
//...
//Message Map entry:
ON_MESSAGE (WM_DELETEALL, OnDeleteAll)
//OnDeleteAll is prototyped as
afx_msg LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam);
//And is implemented as
LRESULT OnDeleteAll(WPARAM wParam, LPARAM lParam){
    //Do What ever you want
    return somevalue;
}
     RegisterWindowMessage()用于定义一个新的窗口消息,必须保证其独一无二。宏ON_REGISTERED_MESSAGE表示该消息。例如:

view plaincopy to clipboardprint?class CMyWnd : public CMyParentWndClass 

public
    CMyWnd(); 

    //{{AFX_MSG(CMyWnd)  
    afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam); 
    //}}AFX_MSG  

    DECLARE_MESSAGE_MAP() 
}; 

static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG"); 

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass) 
    //{{AFX_MSG_MAP(CMyWnd)  
        ON_REGISTERED_MESSAGE(WM_FIND, OnFind) 
    //}}AFX_MSG_MAP  
END_MESSAGE_MAP() 
class CMyWnd : public CMyParentWndClass
{
public:
    CMyWnd();

    //{{AFX_MSG(CMyWnd)
    afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()
};

static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");

BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
    //{{AFX_MSG_MAP(CMyWnd)
        ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

        用该方式定义的消息的范围为0xC000 - 0xFFFF,并采用sendmessage()发送该消息。

程序代码:
view plaincopy to clipboardprint?static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG"); 
//...  
pFindWindow->SendMessage(WM_FIND, lParam, wParam); 
static UINT WM_FIND = RegisterWindowMessage("YOURAPP_FIND_MSG");
//...
pFindWindow->SendMessage(WM_FIND, lParam, wParam);
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 没满月孩孑4天没大便了怎么办 电机轴总是从皮带轮处断裂怎么办 天花板吊顶里的热水管经常坏怎么办 摩托车油箱下面的废油管漏油怎么办 大修机械压力机轴取不下来怎么办 萌侠传说账号密码没了怎么办 车子前保护杠塑料刮花了怎么办 糖猫电话手表关机了找不到了怎么办 小天才电话手表被洗衣机洗了怎么办 小天才电话手表放洗衣机洗了怎么办 小天才电话手表泡水了怎么办 小天才电话手表联不上网怎么办 肺炎用激素治疗后肚子大了怎么办 8岁以下儿童总是低烧不退怎么办? 微博里面的视频不能改变方向怎么办 朗逸导航倒车一体机死机了怎么办 乐淘乐电话手表的二维码没了怎么办 艾蔻儿童手表二维码丢了怎么办 糖猫儿童智能手表二维码丢了怎么办 海信电视用遥控器关了打不开怎么办 创维4k电视遥控器按键坏了怎么办 大疆3s云台陀螺仪错误怎么办 无线路由我用手机上网网速慢怎么办 下载的软件安装包以丢失怎么办 战舰世界航母的飞机恐惧状态怎么办 cad打开图纸不显示轴号怎么办 若背包忘在服务区没拿怎么办 使劲擤鼻涕耳朵耳朵疼了怎么办 用力擤鼻涕一侧的脸肿了怎么办 擦鼻涕太用力耳朵塞住了怎么办 宝宝鼻腔里有鼻涕呼呼响怎么办 黏痰在嗓子眼很干出不来怎么办 宝宝生病好了不久突然又咳嗽怎么办 7个月的宝宝经常生病怎么办 擤鼻涕鼻子周围红肿爆皮怎么办 洗衣机有鼻涕虫洗过的衣服怎么办 手机丢了里边有穿内衣照片怎么办 脸上不知是过敏还是湿疹流水怎么办 一个月的宝宝鼻子不通气怎么办 六个月的宝宝有清水鼻涕怎么办 一岁三个月宝宝流清鼻涕怎么办