windows编程——窗口与消息1

1.WinMain函数

WinMain( )函数与DOS程序的main( )函数基本起同样的作用,但有一点不同的是WinMain( )函数必须带有四个系统传递给它的参数。WinMain()函数的原型如下:

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

第一个参数hInstance是标识该应用程序的句柄。不过句柄又是什么呢?其实就是一个对象或项目的标识符。hIstance唯一地代表了该应用程序,Windows使用它管理内存中的各种对象。它十分重要。在后面的初始化程序主窗口的过程中就需要使用它作为参数。
       第二个参数是hPrevInstance,给它NULL吧,这个参数只是为了保持与16Windows的应用程序的兼容性。
       
第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。比如说,如果我们执行"test hello",则此参数指向的字符串为"hello"
       
最后一个参数是nCmdShow,是用来指定窗口如何显示的整数。关于窗口显示方式的种类,将在下面说明。

2.注册窗口类

一个程序可以有许多窗口,但只有一个是主窗口,它是与该应用程序唯一对应的。

创建窗口前通常要填充一个窗口类WNDCLASS,并调用RegisterClass( )对该窗口类进行注册。每个窗口都有一些基本的属性,如窗口标题栏文字、窗口大小和位置、鼠标、背景色,窗口消息处理函数(后面会讲这个函数)的名称等等。注册的过程就是将这些属性告诉系统,然后再调用CreateWindow( )函数创建出窗口。

  下面列出了WNDCLASS的成员:

  UINT style; //窗口的风格
 
WNDPROC lpfnWndProc; //窗口消息处理函数的指针
 
int cbClsExtra; //分配给窗口类结构之后的额外字节数
 
int cbWndExtra; //分配给窗口实例之后的额外字节数
 
HANDLE hInstance; //窗口所对应的应用程序的句柄
 
HICON hIcon; //窗口的图标
 
HCURSOR hCursor; //窗口的鼠标
 
HBRUSH hbrBackground; //窗口的背景
 
LPCTSTR lpszMenuName; //窗口的菜单资源名称
 
LPCTSTR lpszClassName; //窗口类的名称

WNDCLASS的第一个成员style表示窗口类的风格,它往往是由一些基本的风格通过位的"或"操作(操作符"|")组合而成。下表列出了一些常用的基本窗口风格:

风格

含义

CS_HREDRAW

如果窗口宽度发生改变,重绘整个窗口

CS_VREDRAW

如果窗口高度发生改变,重绘整个窗口

CS_DBLCLKS

能感受用户在窗口中的双击消息

CS_NOCLOSE

禁用系统菜单中的"关闭"命令

CS_SAVEBITS

把被窗口遮掩的屏幕图像部分作为位图保存起来。当该窗口被移动时,Windows使用被保存的位图来重建屏幕图像

第二个成员是lpfnWndProc,给它消息处理函数的函数名称即可,必要时应该进行强制类型转换,将其转换成WNDPROC型。

接下来的cbClsExtra和wc.cbWndExtra一般都可以设为0。

然后的hInstance成员,给它的值是窗口所对应的应用程序的句柄,表明该窗口与此应用程序是相关联的。

下面的hIcon是让我们给这个窗口指定一个图标,这个程序没有设置。

鼠标也没有设置,因为编游戏时的鼠标都是在刷新屏幕时自己画上去的。

hbrBackground成员用来定义窗口的背景色。这里设为CreateSolidBrush (RGB(100, 0, 0)),即暗红色。关于CreateSolidBrush函数,请参阅4.10节。

lpszMenuName成员的值我们给它NULL,表示该窗口没有菜单。

WNDCLASS的最后一个成员lpszClassName是让我们给这个窗口类起一个独一无二的名称,因为Windows操作系统中有许许多多的窗口类。通常,我们可以用程序名来命名这个窗口类的名称。在调用CreateWindow( )函数时将要用到这个名称。

填充完WNDCLASS后,我们需要调用RegisterClass( )函数进行注册;该函数如调用成功,则返回一个非0值,表明系统中已经注册了这个窗口类。如果失败,则返回0 

3.创建窗口

当窗口类注册完毕之后,我们就可以创建一个窗口,这是通过调用CreateWindow( )函数完成的。窗口类中已经预先定义了窗口的一般属性,而在CreateWindow( )中的参数中可以进一步指定窗口更具体的属性。下面举一个例子来说明CreatWindow( )的用法:
 
hwnd= CreateWindow(
 
"Simple_Program",//创建窗口所用的窗口类的名称
 
"ASimple Windows Program", //窗口标题
 
WS_OVERLAPPEDWINDOW,//窗口风格,定义为普通型
 
100,//窗口位置的x座标
 
100,//窗口位置的y座标
 
400,//窗口的宽度
 
300,//窗口的高度
 
NULL,//父窗口句柄
 
NULL,//菜单句柄
 
hInstance,//应用程序句柄
 
NULL); //一般都为NULL

第一个参数是创建该窗口所使用的窗口类的名称,注意这个名称应与前面所注册的窗口类的名称一致。
    
第三个参数为创建的窗口的风格,下表列出了常用的窗口风格:  

风格

含义

WS_OVERLAPPEDWINDOW

创建一个层叠式窗口,有边框、标题栏、系统菜单、最大最小化按钮,是以下几种风格的集合:WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX, WS_MAXIMIZEBOX

WS_POPUPWINDOW

创建一个弹出式窗口,是以下几种风格的集合: WS_BORDER, WS_POPUP, WS_SYSMENU。必须再加上WS_CAPTION与才能使窗口菜单可见。

WS_OVERLAPPED & WS_TILED

创建一个层叠式窗口,它有标题栏和边框。

WS_POPUP

该窗口为弹出式窗口,不能与WS_CHILD同时使用。

WS_BORDER

窗口有单线边框。

WS_CAPTION

窗口有标题栏。

WS_CHILD

该窗口为子窗口,不能与WS_POPUP同时使用。

WS_DISABLED

该窗口为无效,即对用户操作不产生任何反应。

WS_HSCROLL / WS_VSCROLL

窗口有水平滚动条 / 垂直滚动条。

WS_MAXIMIZE / WS_MINIMIZE

窗口初始化为最大化 / 最小化。

WS_MAXIMIZEBOX / WS_MINIMIZEBOX

窗口有最大化按钮 / 最小化按钮

WS_SIZEBOX & WS_THICKFRAME

边框可进行大小控制的窗口

WS_SYSMENU

创建一个有系统菜单的窗口,必须与WS_CAPTION风格同时使用

WS_TILED

创建一个层叠式窗口,有标题栏

WS_VISIBLE

窗口为可见

如果窗口创建成功,CreateWindow( )返回新窗口的句柄,否则返回NULL

4.显示和更新窗口

    窗口创建后,并不会在屏幕上显示出来,要真正把窗口显示在屏幕上,还得使用ShowWindow( )函数,其原型如下:
    BOOL ShowWindow( HWND hWnd, int nCmdShow );
      参数hWnd就是要显示的窗口的句柄。
           nCmdShow是窗口的显示方式,一般给它WinMain()函数得到的nCmdShow的值就可以了。常用的窗口显示方式有:

方式

含义

SW_HIDE

隐藏窗口

SW_MINIMIZE

最小化窗口

SW_RESTORE

恢复并激活窗口

SW_SHOW

显示并激活窗口

SW_SHOWMAXIMIZED

最大化并激活窗口

SW_SHOWMINIMIZED

最小化并激活窗口

ShowWindow( )函数的执行优先级不高,当系统正忙着执行其它的任务时窗口不会立即显示出来。所以我们使用ShowWindow( )函数后还要再调用UpdateWindow(HWND hWnd); 函数以保证立即显示窗口。 

5.消息循环

 WinMain()函数中,调用InitWindow( )函数成功地创建了应用程序主窗口之后,就要启动消息循环,其代码如下:
 
for(;;)
 
{
     
if(PeekMessage(&msg, NULL, 0, 0,PM_REMOVE))  
     
{
         
if ( msg.message==WM_QUIT) break;
         
TranslateMessage(&msg);
         
DispatchMessage(&msg);
 
     }
 
}

Windows应用程序可以接收各种形式的信息,这包括键盘和鼠标的动作、记时器消息,其它应用程序发来的消息等等。Windows系统会自动将这些消息放入应用程序的消息队列中。

PeekMessage( )函数就是用来从应用程序的消息队列中按照先进先出的原则将这些消息一个个的取出来,放进一个MSG结构中去。如果队列中没有任何消息,PeekMessage()函数将立即返回。如果队列中有消息,它将取出一个后返回。

MSG结构包含了一条Windows消息的完整信息,它由下面的几部分组成:
      
HWND hwnd; //接收消息的窗口句柄
     
UINT message; //主消息值
     
WPARAM wParam; //副消息值1,其具体含义依赖于主消息值
     
LPARAM lParam; //副消息值2,其具体含义依赖于主消息值
     
DWORD time; //消息被投递到消息队列的时间
     
POINT pt; //鼠标的位置

该结构中的主消息表明了消息的类型,例如是键盘消息还是鼠标消息等。副消息的含义则依赖于主消息值,比如说如果主消息是键盘消息,那么wParam中存储了是键盘的哪个具体键;如果主消息是鼠标消息,那么LOWORD(lParam)HIWORD(lParam)分别为鼠标位置的xy座标;如果主消息是WM_ACTIVATEwParam就表示了程序是否处于激活状态。这里顺便说一下,定义一个POINT类型的变量curpos后,在程序的任意位置使用GetCursorPos(&curpos)都可以将鼠标座标存储在curpos的成员xy中。

PeekMessage( )函数的原型如下:
 
BOOL PeekMessage (
          
LPMSG lpMsg, //指向一个MSG结构的指针,用来保存消息
     
HWND hWnd, //指定哪个窗口的消息将被获取
     
UINT wMsgFilterMin, //指定获取的主消息值的最小值
     
UINT wMsgFilterMax, //指定获取的主消息值的最大值
     
UINTwRemoveMsg //得到消息后是否移除消息
 
);

PeekMessage( )的第一个参数的意义上面已解释。

 第二个参数是用来指定从哪个窗口的消息队列中获取消息,其它窗口的消息将被过滤掉。如果该参数为NULL,则PeekMessage( )从该应用程序所有窗口的消息队列中获取消息。
     
第三个和第四个参数是用来过滤MSG结构中主消息值的,主消息值在wMsgFilterMinwMsgFilterMax之外的消息将被过滤掉。如果这两个参数均为0,表示接收所有消息。
     
第五个参数用来设置分发完消息后是否将消息从队列中移除,一般设为PM_REMOVE即移除。
 
TranslateMessage( )函数的作用是把虚拟键消息转换到字符消息,以满足键盘输入的需要。DispatchMessage( )函数所完成的工作是把当前的消息发送到对应的窗口过程中去。
     
开启消息循环其实很简单,几乎所有的程序都是按照这个方法。我们完全不必去深究这些函数的作用,只是照抄即可。
     
另外,这里介绍的消息循环开启方法比用GetMessage( )的方法要好一些,因为GetMessage()如果得不到消息会一直等待,结果就耗费了许多宝贵的时间,使程序不能及时刷新。 

初学者如果觉得这一些东西理解起来困难,可以先放着,大概理解一下,安装向导或者照抄下来就好,先学后面一些控件的控制、函数的用法,树立信心和兴趣之后再将它完全理解了
向导相关具体参考<windows编程——编译与向导安装>

————2014年1月23日16:00:32

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章