windows基础应用程序编程(九)控件简介(二)

子窗口和父窗口间的消息传递

    子窗口和父窗口之间如何进行通信呢,答案是肯定,仍然是通过消息来传递,以按钮为例,当我们用鼠标单击按钮的时候,此时子窗口(也就是按钮)会向其父窗口发送一个WM_COMMAND的消息。其中消息的各个参数如下所示:
wParam:低字节表示子窗口的ID,这个值使我们使用CreateWindow时传递的参数,即其中的HMENU项。高字节表示通知码,根据通知码我们可以知道该消息的含义,比如,如果按钮被点击,则对应的通知码是BN_CLICKED。
lParam:子窗口句柄,即我们调用CreateWindow时得到的返回值。
    上面讲到的只是子窗口向父窗口传递消息,同样,父窗口也可以向子窗口发送消息,对于按钮来说,定义了如下的按钮消息
BM_GETCHECK     BM_SETCHECK     BM_GETSTATE     BM_SETSTATE     BM_CLICK     BM_GETIMAGE     BM_SETIMAGE
BM_GETCHECK和BM_SETCECK消息由父窗口发送给子窗口空间,以取得或者设定复选框和单选按钮的选中标记。BM_GETSTATE和BM_SETSTATE消息表示按钮处于正常状态还是按下状态。BM_SETSTYLE消息允许在按钮建立之后改变按钮样式。(发送消息使用SendMessage消息)比如我们在来自控件的WM_COMMAND消息时,我们可以用如下的代码来反转复选框的状态。
SendMessage((HWND)lParam, BM_SETCHECK, (WPARAM)!SendMessage((HWND)lParam, BM_GETCHECK, 0, 0), 0);

编辑类

    同样,我们可以再CreateWindow中以edit作为窗口类来建立一个编辑控件,和静态子窗口控件一样,我们可以通过设置窗口样式ES_LEFT、ES_RIGHT和ES_CENTER来指定这些编辑控件的文字是左对齐、右对齐还是居中。
    默认状态下,编辑控件是单行的,我们可以设置ES_MULTILINE来建立多行编辑控件。如果我们想要使用自动水平或者垂直滚动的编辑控件,可以采用样式ES_AUTOHSCROLL或ES_AUTOVSCROLL。
    同样,编辑控件给父窗口消息处理程序发送WM_COMMAND消息,并且,各参数的含义和按钮控件的含义一样。其中,常见编辑控件的通知码如下:
EN_SETFOCUS:编辑控件已经获得输入焦点
EN_KILLFOCUS:编辑控件已经失去输入焦点
EN_CHANGE:编辑控件的内容将改变
EN_UPDATE:编辑控件的内容已经改变
EN_HSCROLL:编辑控件的水平滚动条已经被按下
EN_VSCROLL:编辑控件的垂直滚动条已经被按下
父窗口可以向编辑控件发送剪切、复制、或者清除目前被选择文字等消息。如:
SendMessage(hwndEdit, WM_CUT, 0, 0);
具体有哪些消息,可以查看MSDN。

列表框

    下面介绍另外一个常用的控件,列表框控件,列表框(List Box)是一个允许用户从已有的项目中进行选择的控件。它可以是单选的也可是是多选的。
    同样,如果我们需要建立列表框控件,仍然需要使用CreateWindow函数,并把“listbox”作为窗口类,但需要注意的是,默认的列表框是不向父窗口发送WM_COMMAND消息的,如果我们需要这样做,那么就必须让列表框控件的样式包含LBS_NOTIFY。同样,如果想要支持多选,那么需要使用样式LBS_MULTIPLESEL。其中我们最常用的样式的LBS_STANDARD,这是以下几种样式的组合。
LBS_NOTIFY | LBS_SORT | WS_VSCROLL | WS_BORDER
我们可以通过SendMessage为列表框发送加入字符串消息来把一个字符串放入到列表框中,字符串通常是从0开始计数的,其中0对应于列表框中最顶上的项。如下所示:
SendMessage( hwndList, LB_ADDSTRING, 0, (LPARAM)szString );
也可是使用LBS_INSERTSTRING消息来插入字符串,但这时,我们需要传入一个iIndex,即插入的位置索引。
SendMessage( hwndList, LB_INSERTSTRING, iIndex, (LPARAM)szString );
同样,如果需要删除指定字符串,我们需要使用LB_DELETESTRING消息。
清除列表框内容使用LB_RESETCONTENT消息
还有一些常用的消息如下所示:
LB_GETCOUNT:获取列表框中有多少项
LB_SELECTSTRING:查找字符串
LB_GETCURSEL:获得当前选项的索引
LB_GETTEXTLEN:获得列表框中字符串的长度
LB_GETTEXT:把列表框中的选择字符串复制到一个文字缓冲区中,
    当然还有很多其他的消息和控件,以及参数的含义在这里不再赘述,只是简单的介绍一个概念,具体使用查看MSDN。
总之,对于控件来说,
1、因为控件也是一种窗口,所以我们仍然使用CreateWindow函数来进行创建,只是使用的窗口类不需要我们自己去定义,而是使用系统预定义好的一些窗口类。
2、我们在CreateWindow中使用控件,一般需要把控件的类型设置为WS_CHILD | WS_VISIBLE,如果不设置WS_VISIBLE,那么我们需要使用ShowWindow函数来显示窗口。
3、控件一般给父窗口发送WM_COMMAND消息,其中wParam低字节表示控件ID,高字节表示通知码,父窗口通过通知码来获取控件的状态,从而做出相应的反应。lParam表示控件的句柄。
4、我们可以使用控件ID或者控件的句柄来识别是哪一个控件,但不同的控件ID可能是相同的,但句柄是唯一的。
5、父窗口可以通过SendMessage发送对应的控件消息来传递给控件。控件结束消息,使用预定义好的窗口类中的窗口处理函数来进行处理。

实例:

    下面用Windows程序设计一书中的一个示例来简单的运用一下编辑控件,该示例是一个简单的文本编辑器,我们可以在这个基础上运用上面所讲的知识,来继续扩充功能,添加菜单等等。代码如下:
#include 
        
#define ID_EDIT     1     

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);    

TCHAR szAppName[] = TEXT ("PopPad1") ;      

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
        
                   PSTR szCmdLine, int iCmdShow)
        
{
           HWND                  hwnd ;
           MSG                      msg ;
           WNDCLASS              wndclass ;
   
           wndclass.style = CS_HREDRAW | CS_VREDRAW ;
           wndclass.lpfnWndProc = WndProc ;
           wndclass.cbClsExtra = 0 ;
           wndclass.cbWndExtra = 0 ;
           wndclass.hInstance = hInstance ;
           wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
           wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
           wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
           wndclass.lpszMenuName = NULL ;
           wndclass.lpszClassName = szAppName ;

           if (!RegisterClass (&wndclass))
           {
                  MessageBox (  NULL, TEXT ("This program requires Windows NT!"),
                                               szAppName, MB_ICONERROR) ;
                  return 0 ;
           }
        
    hwnd = CreateWindow (szAppName, szAppName,
                       WS_OVERLAPPEDWINDOW,     
                       CW_USEDEFAULT, CW_USEDEFAULT,      
                       CW_USEDEFAULT, CW_USEDEFAULT,      
                       NULL, NULL, hInstance, NULL) ;
  ShowWindow (hwnd, iCmdShow) ;    
  UpdateWindow (hwnd) ;

           while (GetMessage (&msg, NULL, 0, 0))      
           {
                  TranslateMessage (&msg) ;
                  DispatchMessage (&msg) ;
           }
           return msg.wParam ;
}
        

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)       
{     
           static HWND hwndEdit ;
           switch (message)       
           {        
           case   WM_CREATE :        
                  hwndEdit = CreateWindow (TEXT ("edit"), NULL,       
               WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |       
               WS_BORDER | ES_LEFT | ES_MULTILINE |      
               ES_AUTOHSCROLL | ES_AUTOVSCROLL,    
               0, 0, 0, 0, hwnd, (HMENU) ID_EDIT,      
              ((LPCREATESTRUCT) lParam) -> hInstance, NULL) ;      
                  return 0 ;

           case   WM_SETFOCUS :        
                  SetFocus (hwndEdit) ;       
                  return 0 ;
     
           case   WM_SIZE :        
           MoveWindow (hwndEdit, 0, 0, LOWORD (lParam), HIWORD (lParam), TRUE) ;      
                  return 0 ;    
        
           case   WM_COMMAND :    
                  if (LOWORD (wParam) == ID_EDIT) 
               if (HIWORD (wParam) == EN_ERRSPACE ||    
                   HIWORD (wParam) == EN_MAXTEXT)
        
            MessageBox (hwnd, TEXT ("Edit control out of space."),    
                   szAppName, MB_OK | MB_ICONSTOP) ;      
                  return 0 ;
  
           case   WM_DESTROY :      
                  PostQuitMessage (0) ;      
                  return 0 ;    
          }     
           return DefWindowProc (hwnd, message, wParam, lParam) ;
        
}



你可能感兴趣的:(windows基础应用程序编程)