Windows程序设计--窗口与消息
2015-09-09 14:43
585 查看
进行Windows程序设计时,其实就是在进行一种面向对象的编程。在面向对象中,对象是代码和数据的组合,一个窗口也是一个对象。
在用户眼中,窗口是屏幕上的对象,并可借助键盘或鼠标直接与之进行交互。
用户对窗口的输入以“消息”的形式传递给窗口,而窗口也借助消息来与其他窗口进行通信。
窗口创建看似容易,调用CreateWindow函数即可。
但是在创建窗口之前,需要注册一个窗口类。而窗口类又确定了处理窗口消息的窗口过程。
多个窗口可以同时基于某一窗口类来创建。注册窗口类必须调用RegisterClass函数。该函数只有一个参数,即一个指向WNDCLASS类型的结构的指针。下面我们看看这个结构:
首先是ASCII版本:
其次是Unicode版本:
可以看到只有最后两个字段不同,Unicode被定义为宽字符的常量字符串。
在WNDCLASS中最重要的两个字段是第二个lpfnWndProc和最后一个lpszClassName。
第二个字段是基于该窗口类的所有窗口的窗口过程的地址。
最后一个字段是窗口类的名称。
接下来该是创建了:
创建之后,就该是窗口的显示了。即函数ShowWindow(hwnd, iCmdShow);
第一个参数就是CreateWindow所创建的窗口的句柄。
第二个参数就是WinMain函数所接受的iCmdShow值。
然后调用UpdateWindow(hwnd)进行窗口客户区重绘。
在UpdateWindow后,新建的窗口在屏幕中便完全可见了。
此时,该程序必须能够接收来自用户的键盘输入和鼠标输入。是如何做到的呢?
Windows为当前在其中运行的每一个Windows程序都维护了一个“消息队列”。当输入时间发生后,Windows会自动将这些事件转换为“消息”,并将其放置在应用程序的消息队列中。
应用程序通过如下代码循环:
其中msg是一个结构变量,定义如下:
上诉结构中的POINT是另一种结构:
下面介绍真正有意思的事情–窗口过程
一个windows程序可以包含多个窗口过程,但一个窗口过程总是与一个通过调用RegisterClass注册的特定窗口类相关联。
窗口过程总是按照如下定义:
窗口过程函数的四个参数与MSG结构的4个字段一一对应。
第一个参数:表示接收消息的窗口的句柄
第二个参数:消息标识符
最后两个参数:32位的消息参数
最后就是消息处理了:
在用户眼中,窗口是屏幕上的对象,并可借助键盘或鼠标直接与之进行交互。
用户对窗口的输入以“消息”的形式传递给窗口,而窗口也借助消息来与其他窗口进行通信。
窗口创建看似容易,调用CreateWindow函数即可。
但是在创建窗口之前,需要注册一个窗口类。而窗口类又确定了处理窗口消息的窗口过程。
多个窗口可以同时基于某一窗口类来创建。注册窗口类必须调用RegisterClass函数。该函数只有一个参数,即一个指向WNDCLASS类型的结构的指针。下面我们看看这个结构:
首先是ASCII版本:
typedef struct tagWNDCLASSA{ UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCSTR lpszMenuName; LPCSTR lpszClassName; } WNDCLASS, *PWNDCLASS;
其次是Unicode版本:
typedef struct tagWNDCLASSW{ UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINSTANCE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCWSTR lpszMenuName; LPCWSTR lpszClassName; } WNDCLASS, *PWNDCLASS;
可以看到只有最后两个字段不同,Unicode被定义为宽字符的常量字符串。
在WNDCLASS中最重要的两个字段是第二个lpfnWndProc和最后一个lpszClassName。
第二个字段是基于该窗口类的所有窗口的窗口过程的地址。
最后一个字段是窗口类的名称。
接下来该是创建了:
hwnd = CreateWindow(szAppName, //窗口类的名称 TEXT("The Hello Program"), //窗口标题 WS_OVERLAPPEDWINDOW, //窗口风格 CW_USEDEFAULT, //初始x坐标 CW_USEDEFAULT, //初始y坐标 CW_USEDEFAULT, //初始x方向尺寸 CW_USEDEFAULT, //初始y方向尺寸 NULL, //父窗口句柄 NULL, //窗口菜单句柄 hInstance, //程序实例句柄 NULL); //创建参数
创建之后,就该是窗口的显示了。即函数ShowWindow(hwnd, iCmdShow);
第一个参数就是CreateWindow所创建的窗口的句柄。
第二个参数就是WinMain函数所接受的iCmdShow值。
然后调用UpdateWindow(hwnd)进行窗口客户区重绘。
在UpdateWindow后,新建的窗口在屏幕中便完全可见了。
此时,该程序必须能够接收来自用户的键盘输入和鼠标输入。是如何做到的呢?
Windows为当前在其中运行的每一个Windows程序都维护了一个“消息队列”。当输入时间发生后,Windows会自动将这些事件转换为“消息”,并将其放置在应用程序的消息队列中。
应用程序通过如下代码循环:
while(GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg);//用于从消息队列中对消息进行检索 DispatchMessage(&msg);//将msg结构返还给Windows以进行某些键盘消息的转换 }
其中msg是一个结构变量,定义如下:
typedef struct tagMSG { HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt; } MSG, *PMSG;
上诉结构中的POINT是另一种结构:
typedef struct tagPOINT { LONG x; LONG y; } POINT, *PPOINT;
下面介绍真正有意思的事情–窗口过程
一个windows程序可以包含多个窗口过程,但一个窗口过程总是与一个通过调用RegisterClass注册的特定窗口类相关联。
窗口过程总是按照如下定义:
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
窗口过程函数的四个参数与MSG结构的4个字段一一对应。
第一个参数:表示接收消息的窗口的句柄
第二个参数:消息标识符
最后两个参数:32位的消息参数
最后就是消息处理了:
switch(message) { case WM_CREATE: [处理WM_CREATE消息] return 0; case WM_PAINT: [处理WM_PAINT消息] return 0; case WM_DESTROY: [处理WM_DESTROY消息] return 0; } return DefWindowProc(hwnd, message, wParam, lParam);
相关文章推荐
- Java编译错误“No enclosing instance of type AA is
- Kafka设计解析(三):Kafka High Availability (下)
- 使用adb工具截图和传送图片
- [刷题]Trailing Zeros
- CSS中关于快速定位和覆盖当前点选器的办法
- elasticsearch的实现全文检索
- [Objective-C]C语言特性(函数,变量,编译指令,指针,块)
- Mac 下安装使用Android Studio
- 计蒜客 第13题:整数转换成罗马数字
- Redis主从配置-Linux环境
- Objective-C学习笔记之id和instancetype
- Windows程序设计--窗口与消息
- iOS 登录与注册的界面跳转
- 我学的是设计模式的视频教程——装饰图案,装饰图案VS代理模式
- 闭包和沙箱
- HelloSpark.scala
- Redis自增实现计数
- 小小的自豪
- 小小的自豪
- map-combine过程解