分享

windows窗口的创建

 昵称1088221 2010-07-15
一、WINDOWS的消息和窗口简介:
1、什么是windows在这里我就不介绍了,但是作为一个程序员我们要知道WINDOWS最重要的一个也是我们程序员常用的一个东西就是消息。窗口是以消息的形式输入的,窗口也用消息与其它窗口通讯。
2、我们常会说windows给程序发送了一个消息,其实这是指windows调用程序中的一个函数,该函数的参数描述了这个特定消息。这种位于windows程序中的函数称为“窗体消息处理程序”。程序建立的每一个窗体都有相关的窗口消息处理程序。这个窗口消息处理程序是一个函数,既可以在程序中,也可以在动态链接库中。Windows通过调用窗口消息处理程序来给窗体发送消息。窗口消息处理程序根据此消息进行处理,然后将控制传回给windows。
3、在对象导向的程序设计中,对象是程序与数据的组合。窗口是一种对象,其程序是窗口消息处理程序。数据是窗口消息处理程序保存的信息和windows为每个窗口以及系统中那个窗口类别保存的信息。
4、windows程序开始执行后,windows为该程序建立一个“消息队列”。这个消息队列用来存放该程序可能建立的各种不同窗口的消息。程序中有一小段程序代码,叫做“消息循环”,用来从队列中取出消息,并且将它们发送给相应的窗口消息处理程序。有些消息直接发送给窗口消息处理程序,不用放入消息队列中。
二、一个真正的windows程序:
1、代码如下:
#include <windows.h>
LRESULT CALLBACK WndPro(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) ;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd){
   static TCHAR szAppName[]=TEXT("helloWin");//一个静态的不确定是不是16位还是8位的UNICODE字符串
   HWND hwnd;                                           //窗口句柄
   MSG msg;                                                       //消息结构
   WNDCLASS wndclass ;                                   //窗口类别结构
   wndclass.style =CS_HREDRAW|CS_VREDRAW;//当长高改变成重绘区域型
   wndclass.lpfnWndProc=WndPro;//一个指向消息循环的函数指针
   wndclass.cbClsExtra=0;                     //在窗口类别结构和windows内部保存的窗
   wndclass.cbWndExtra=0;                   //口结构中预留一些额外空间
   wndclass.hInstance=hInstance;                //这个程序是hinstance的一个子集
   wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);//使用什么图标
   wndclass.hCursor=LoadCursor (NULL,IDC_ARROW);//使用什么鼠标样式
   wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_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,TEXT("The Hello Program"),
    WS_OVERLAPPEDWINDOW,//这是一个多样式组合
    CW_USEDEFAULT,CW_USEDEFAULT,
    CW_USEDEFAULT,CW_USEDEFAULT,//都是windows的内定尺寸
    NULL,NULL,hInstance,NULL);//建立窗口类型大小等
   ShowWindow(hwnd,nShowCmd);//显示窗口以nShowCmd来显示
   while (GetMessage(&msg,NULL,0,0))//这是从消息队列中取出一条消息
   {//消息的发送和分派最上层窗口用NULL
    TranslateMessage(&msg);
    DispatchMessage(&msg);//在这里会调用到wndPro
   }
   return msg.wParam;
 
}
 
LRESULT CALLBACK WndPro(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
   HDC hdc;
   PAINTSTRUCT ps;                                                 //绘图结构
   RECT rect;                                                             //矩形结构
   switch(message)
   {
   case WM_CREATE:
// PlaySound(TEXT("hellowin.wav"),NULL,SND_FILENAME|SND_ASYNC);
    break;
   case WM_PAINT:
    hdc=BeginPaint(hwnd,&ps);                           //开始画图
    GetClientRect(hwnd,&rect);   
;   // 得到用户区
    DrawText(hdc,TEXT("HELLO WINDOWSXP"),-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);// 线型输出到中间
    EndPaint(hwnd,&ps);
    break;
   case WM_DESTROY:
    PostQuitMessage(0);// 发出一个退出消息
    break;
   }
   return DefWindowProc(hwnd,message,wParam,lParam);
}
2、代码分析:
(1)、在这里你除了winMain你还可以看到一个WndPro的函数这个函数就是传说中的消息处理函数,即消息循环就在这里运行的也是一个程序的心脏,有了他程序才可以得到正常的运行,他在窗口注册类的类里就被移植入窗口类中wndclass.lpfnWndProc=WndPro;要先申明后使用。
(2)、在这里我还要说一下下CreateWindow和WNDCLASS也就是建立窗口和注册窗口的联系,他们之间就好比造车厂和设计车的关系,RegisterClass函数注册了一个WNDCLASS的对象,然后CreateWindow通过其中的lpClassName这个参数也就是WNDCLASS对象的lpszClassName与窗口类联系起来,lpszClassName都是字符串的类型。
(3)、windows函数的调用:这个基本的框架里我们调用了18个windows 函数如下
LoadIcon                           加载图标代程序使用
LoadCursor                加载鼠标光标供程序使用
GetStockObject           取得一个图形对象
RegisterClass                     为程序窗口注册窗口类别
MessageBox               显示消息框
CreateWindow            根据窗口类别建立一个窗口
ShowWindow                     在屏幕上显示窗口
UpdateWindow            指示窗口自我更新
GetMessage                从消息队列中取得消息
TranslateMessage        转译某些键盘消息
DispatchMessage        将消息发送给窗口消息处理程序
PlaySound                  播放一个声音文件
BeginPaint                  开始绘制窗口
GetClientRect                     取得窗口显示区域的大小
DrawText                          显示字符串
EndPaint                            结束绘制窗口
PostQuitMessage         在消息队列中插入一个退出消息
DefWindowProc:         执行内定消息处理
(4)、在这个函数里面有很多大小写字母宏定义:这些解释一下下
在上面的函数中出现了如下几个大写字母宏定义:
CS_HREDRAW           DT_VCENTER             SND_FILENAME
CS_VREDRAW        IDC_ARROW            WM_CREATE
CW_USEDEFAULT     IDI_APPLICATION      WM_DESTROY
DT_CENTER                 MB_ICONERROR         WM_PAINT
DT_SINGLELINE              SND_ASYNC           WS_OVERLAPPEDWINDOW
           前缀:    类别                                                 使用
           CS          窗口类别样式    WNDCLASS.style=CS_HREDRAW|CS_VREDRAW;
           CW         建立窗口              CreateWindow---(CW)
           DT         绘制文字              DrawText----(DT)
           IDI         图示ID                 LoadIcon(….)
           IDC        鼠标ID                 LoadCursor()
           MB         消息框
BACKGROUND: #d9d9d9">                  MessageBox------MB
           SND       声音                      PlaySound ( …… )
           WM        窗口消息               WindowsMessage-------(WM)
           WS         窗口样式               WindowStyle-----(WS)
 (5)、我们常会问WPARAM和LPARAM有什么区别干什么用:
其实这两个参数是win16和win32并存时留下的产物现在都是32位了,原来wParam(WORD)是一个16位的lParam(LONG)是32位的,现在的WPARAM和LPARAM都是MS重新定义的,他们通常是与一个消息有关的常量值如下:
wParam   通常是一个与消息有关的常量值,也可能是窗口或控件的句柄。 
lParam   通常是一个指向内存中数据的指针。由于wParam,lParam和指针都是32位的,需要时可以强制类型转换。具体表示什么,与message相关,他们是事先定义好的。
(6)、WndPro函数传回一个形态为LRESULT的值,议该值简单地被定义为一个LONG,在这里WndPro函数被指定成一个CALLBACK形态,其实也是一个和WINAPI一样的宏定义他是一个_stdcall一个从右到左的压栈方式,也就是传说中的回调函数(纸老虎不用怕)。
3、句柄简介:
句柄是一个(通常为32位的)整数,它代表一个对象。Windows中的够本类似传统C或MS-Dos程序设计中使用的文件句柄。程序几乎总是通过呼叫window函数取得句柄。程序在函数中使用够本,用以代表对象。句柄值对程序来说是无关紧要的,但是windows对于这个代号来说他就可以利用这个代号(句柄)使用相对应的对象。
一句话句柄是什么,比如你是一个对象那么句柄就是你的名字,如果windows要叫你去买酱油那么他会给你说:“XX句柄去买酱油”,和叫对象去买酱油的效果是一样,但是用了句柄会更好管理。(我不知道这样理解是否会好一点!)
三个大写标识符,用于不同形态的句柄
     标识符                         含义
     HINSTANCE                执行实体(程序自身)句柄
     HWND                         窗口句柄
     HDC                            设备内容句柄
句柄用的很频繁比如:HICON(图标句柄)、HCURSOR(鼠标光标句柄) 、
HBRUSH(画刷句柄)、windows中的每个窗口都有一个够本,程序用够本来使用窗口窗体句柄是windows程序所处理最重要的句柄之一。
4、我顺便也说一下instance吧,其实这就相当于是你运行QQ整个QQ就是一个instance!
三、注册窗口类别:
窗口依照某一窗口类别建立,窗口类别用以标识处理窗口消息的消息处理程序。
窗口类别定义了窗口消息处理程序和依据引类别建立的窗口的其它特征。在建立窗口时,要定义一些该窗口所独有的特征。
在为程序建立窗口之前,必须首先调用RegisterClass注册一个窗口类别。该函数只需要一个参数,即一个指向形态为WNDCLASS的结构指针。些结构包括两个指向字符串的字段(LPCTSTR lpszMenuName; LPCTSTR lpszClassName;--ASCII。 LPCWSTR lpszMenuName ;LPCWSTR lpszClassName;--UNICODE)因此结构在WINUSER.H表文件中定义了两种不同的方式(ASCII,UNICODE)在编程过程我们不必去理会!因为在预定义时已经处理过了(WNDCLASSA,WNDCLASSW---都用WNDCLASS就行)!
       在窗体类定义中最重要的是lpfnWndProc和最后一个字段lpszClassName。
四、窗口类别
他定义了窗口的一般特征,因此可以使用同一窗口类别建立许多不同的窗口
R: blue">CreateWindow 建立窗口时,可能指定有关窗口的更详细的信息。传递给RegisterClass函数的信息会在一个数据结构中设定好,而传递给CreateWindow函数的信息会在函数单独的参数中设定好。
五、消息循环:
Windows为当前执行的每个windows程序维护一个“消息队列”。在发生输入事件后,windows将事件转换为一个消息并将消息放入程序消息队列中。程序通过执行一块称之为消息循环的程序代码从消息队列中取出消息。
在这里我们了解一下下MSG结构:
Typedef struct tagMSG{
       HWND hwnd;               //接收消息的窗口句柄
       UNIT message;             //消息标识符WM_XXXX
       WPARAM wparam;       //32位其含义和数值根据消息的不同而不同
       LPARAM lparam;         
       DWORD time;              //消息放入消息队列中的时间
       POINT pt;                    //消息放入消息队列时的鼠标坐标
}MSG,*PMSG;
BOOL GetMessage(
 LPMSG lpMsg,         // address of structure with message
 HWND hWnd,           // handle of window
 UINT wMsgFilterMin, // first message
 UINT wMsgFilterMax   // last message
);
这个调用付给windows一个指标,指向名这msg的MSG结构。lpMsg是一个消息地址,hWnd如果为NULL表示程序接收它自己建立的所有窗口的所有消息,Windows用从消息队列中取出的下一个消息来填充消息结构的各个字段。只要从消息队列中取出消息的message字段不为WM_QUIT,GetMessage就传回一个非零值。
BOOL TranslateMessage(
 CONST MSG *lpMsg   // address of structure with message
);
将msge结构传给windows,进行一些键盘转换
LONG DispatchMessage(
 CONST MSG *lpmsg   // pointer to structure with message
);
又将msg结构回传给windows。然后,windows将该消息发送给适当的窗口消息处理程序,让它进行处理。这里就是windows将会调用消息处理程序,也就是这个窗口的wndPro函数。处理完消息之后,WndProc传回到windows,此时window还停留在despatchMessage调用中,在结束dispatchMessage调用的处理之后,windows回到GetMessage调用开始消息循环。
六、窗口消息处理程序:
在上面我们介绍了一个窗口的产生过程和动作过程:注册窗口类别,建立窗口,然后在屏幕上显示窗口,程序进入消息循环,然后不断从消息队列中取出消息来处理。实际的动作发生在窗口消息处理程序中。窗口消息处理程序确定了在窗口的显示区域中显示以及窗品怎样响应使用者输入。窗口消息处理程序可任意命名,一个windows程序中可以包含多个窗口消息处理程序。一个窗口消息处理程序总与调用 的registerClass注册的特定窗口类别相关联。createWindow函数根据特定窗口类别建立一个窗口。但依据一个窗口类别,可以建立多个窗口。
窗口消息处理程序总是定义为如下形式:
LRESULT CALLBACK WndProc(HWND hwnd,UNIT message,
WPARAM wparam,LPARAM lparam)这四个参数和Msg结构的前四个字段是相同的。
程序通常不直接呼叫窗口消息处理程序,中消息处理程序通常由windows本身调用。窗口消息处理程序在处理消息时,必须传回窗口消息处理程序不处理的所有消息应传给名为DefWindowProc的Window函数。Wndproc只先择处理三种消息:WM_CREATE,WM_PAINT,WM_DESTROY。
WM_CREATE:处理进行一次窗口初始化。
WM_PAINT:当窗口显示区域的一部分或者全部内容必要更新显示或无效时,将由这个消息通知程序。什么叫无效,无效就是说如果窗口调用updateWindows时例如在窗口类中我们写的style=CS_HREDRAW|CS_VREDRAW这表示在窗口大小改变后就把整个窗口显示内容变为无效调用updateWindows进行重绘。在对WM_PAINT的处理几乎总是从一个BeginPaint(hwnd,&ps)调用开始,以EndPaint(hwnd,&ps)结束,ps包含一些窗口消息处理程序可以用来更新显示区域的内容。在BeginPaint调用中,如果显示区域的前景还没被删除则由windows来删除,它使用窗口类别的WNDCLASS的结构中的hbrBackground字段中指定的画刷来删除前景。BeginPain返回一个只能在当前区域绘图的设备内容句柄。EndPain释放设备内容句柄。GetClientRect(hwnd,&rect)rect是返回一个窗口显示区域的尺寸。
WM_DESTROY:该消息是使用者单击Close按钮或者程序的系统菜单上选择Close时发生的。在这里用的是PostQuitMessage(0)来生效的。该函数在程序的消息队列中插入一个WM_QUIT消息使GetMessage得到一个WM_QUIT的消息,它传回0,终止程序然后执行return msg.wparam;
七、队列化消息与非队列化消息:
       Windows给窗口发送消息,这意味着windows调用窗口消息处理程序。但是,windows程序也有一个消息循环,它调用GetMessage从消息队列中取出消息,并且调用dispatchMessage将消息发送给窗口消息处理程序。
       消息被分为“队列化的”和“非队列化的”。
1、 队列化的消息:是由windows放入程序消息队列中的。在程序的消息循环中,重新传回并分配给窗口消息处理程序。如键盘消息,WM_PAINT windows消息等。
2、 非队列化的消息在windows调用窗口时直接送给窗口消息处理程序。非队列化消息多来自己于调用windows函数如CreateWindows,键盘或鼠标输入时发出的队列化消息信号,也能在非队列化消息中出现。
3、 队列化的消息被发送给消息队列,而非队列的消息则发送给窗口消息处理程序。
任何发问下,窗口消息处理程序都将获得窗口所有的消息――包括队列和非队列化的消息。窗口消息处理程序是窗口的消息中心。
4、在许多情况下,窗口消息处理程序必须保存它从消息中取得的信息,并在处理另一个消息时使用这些信息。这些信息可以储存在窗口的静态变量或整体变量中。
 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多