当前位置:C++技术网 > 精选软件 > 图解子窗口控件和父窗口是如何通信的:1 子窗口控件向父窗口发送消息

图解子窗口控件和父窗口是如何通信的:1 子窗口控件向父窗口发送消息

更新时间:2016-02-03 20:33:33浏览次数:1+次

    当你在父窗口中创建了一个子窗口控件,这个子窗口控件就粘在父窗口上了。为什么是这样呢?这得从子窗口控件说起。
    多窗口的编程部分,涉及到的东西很多,所以,需要一个个来分析清楚。不要急着一下子就将多窗口的编程搞得清清楚楚,我也没有办法一下子将所有的技术点都分析出来。这里先解释一下子窗口控件。
    为什么不叫做控件,还要带上子窗口这个词呢?当然是有原因的了。控件也是窗口,只是它是由系统窗口类创建出来的。我们所说的控件,通常指的是系统提供的公共控件,如按钮、编辑框等。这类控件,可以使用在各种语言各种程序框架中,只要是Windows系统,都可以使用。公共控件的公共是相对于整个Windows操作系统而言的。
    因为我们是将控件用作父窗口的子窗口,也就是与父窗口建立父子窗口关系,所以,控件也成为了子窗口。所以,在窗口上看到的控件,都是子窗口,也就可以叫做子窗口控件。
    当然,如果创建控件时,不指定窗口风格WM_CHILD,那么控件将被创建成独立的窗口。独立的窗口也就表示窗口不会贴在其他窗口上,也不会局限于其他窗口的客户区范围内。此时,控件窗口就不是子窗口,所以此时依然是正常的窗口,只是它的窗口过程是系统写好了的。此时,最多只能叫做控件窗口。
    对待控件窗口,就只要和对待普通窗口一样即可。而我们这里讨论的就是子窗口控件,不仅是由系统窗口类创建的窗口,即控件,而且还会作为其他窗口的子窗口。当然作为标准控件,就不要加入其他的窗口风格。创建控件时,加入WS_CHILD、WS_VISIBLE和控件相关的控件风格即可。
    那么说清楚了子窗口控件,那么就看看子窗口是如何和父窗口通信的吧。子窗口控件放在父窗口中,要与父窗口通信,告诉控件自身的情况,让父窗口知道在控件上都发生了些什么,这样父窗口才好做出其他处理,比如完成一个功能。举个例子来说,在父窗口中放置一个按钮,比如弹出一个警告信息。我们单击按钮的时候,父窗口是不知道的。控件虽然成了子窗口,但是它还是可以独立的接受消息。因为子窗口在父窗口之上,所以优先获取在窗口之上的消息。
    所以,按钮控件被单击后,按钮就得到了一个鼠标单击消息WM_LBUTTONDOWN,只不过这个消息我们没有办法直接处理。因为按钮窗口类的窗口过程都是系统提供好的,所以我们无法直接干预。我们也不能在父窗口的窗口过程写,因为父窗口的窗口过程,处理的是父窗口上的单击。然而,按钮控件被单击,压根就没有单击到父窗口,而是单击到按钮控件上了。不仅在父窗口窗口过程无法处理按钮控件单击的消息,这个消息处理逻辑就是错误的。这是很多人犯的错误,我曾经也是这样。
    那么按钮控件被单击后,父窗口是如何知道的呢?答案就是:控件发消息告诉父窗口的。按钮可以发消息说:“爸呀,我被人戳了,戳的好疼,帮忙搞定一下吧。”。父窗口得到消息后,赶紧弹出一个警告:“滚!不要再戳我儿子了!”。你以为这是搞笑的描述,事实上,就是这么个过程哦。
    控件虽然依附在父窗口上,实际上它依然是一个完整的窗口,就像儿子小时候住在父亲的家里,儿子个人还是一个完整的个人,并不会因为和父亲住在一起而不完整。当同学在学校欺负儿子的时候,儿子回家告诉父亲,然后父亲赶紧打电话给老师要求学校严肃处理。
    我实际上描述了两遍,确实是因为这里有太多人懵懵懂懂的。希望用这个生活的例子,给你很形象的理解。那么儿子是如何告诉父亲的呢?答案就是WM_COMMAND消息。
    下面来看子窗口控件向父窗口发送消息的示意图:

        子窗口控件向父窗口发送消息的示意图
       【子窗口控件向父窗口发送消息的示意图】
    从图中可以看到,所有的控件,要向父窗口发送消息,都是发送的WM_COMMAND消息!当然,菜单也是。不过菜单与窗口并不是父子窗口关系,所以没有列入图中。除了静态标签控件外的其他公共控件,都会在控件被操作后,向父窗口发送WM_COMMAND。为什么静态标签例外呢?因为它设计出来就是只是安静的展示一些信息的,不需要交互,如果确实需要交互,就用其他控件。如果你确实需要交互,则要给静态标签设置SS_NOTIFY静态标签风格,这样静态标签就会主动给父窗口发消息了。
    在WM_COMMAND消息的参数中,WPARAM参数的低字部分携带了控件的ID。如果是菜单的单击,就是菜单的ID。WPARAM参数的高字部分则是通知码。控件ID或者菜单ID用于识别单击来自于哪一个控件。因为一个窗口中可以有很多个控件。至于控件是被戳了还是被人关心了,当然要有区分。不然父窗口不知道该如何处理。这就是通知码的作用。通知码用于区别按钮是被怎么了!不同的控件,通知码不一样,使用场景也不一样,所以需要具体的控件具体分析。这里你只需要感性的认识到通知码有什么用即可。
    提取控件ID使用LOWORD宏,提取通知码用HIWORD宏即可,代码如下:

int id = LOWORD(wParam);
int iNotice = HIWORD(wParam);
     而父窗口要告诉子窗口控件怎么处理现在的情况,则需要子窗口控件的窗口句柄。所以在LPARAM参数中,已经携带了子窗口控件的窗口句柄。这个句柄是子窗口控件让父窗口好给自己发消息,因为发消息要用窗口句柄。
    那么你会想,子窗口要发消息给父窗口WM_COMMAND消息,是如何执行的呢?这就是系统提供好的了。系统窗口类也是系统提供的,这都是系统已经事先做好了的,所以,在父窗口创建子窗口控件的时候建立了父子窗口关系,系统自然就会将这些信息存储起来。然后子窗口控件被操作后,系统就会去查找子窗口控件的父窗口的句柄,然后用这个句柄来发送消息,就将子窗口的消息发送给了父窗口。