全国 【切换城市】欢迎您来到装修百科!
关注我们
我要装修

2.2.7 Windows程序关闭窗口的实现过程

发布:2024-09-10 浏览:35

核心提示:2.2.7 第14练:处理WM_DESTROY消息#include <windows.h>LRESULT

2.2.7 第14练:处理WM_DESTROY消息#include <windows.h>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回调函数int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){……(略)return msg.wParam;//msg.wParam 来自一条表示退出的消息,返回这个值给系统}//窗口回调函数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){HDC hDC; //设备环境——绘图的地方PAINTSTRUCT ps; //绘图结构体变量RECT rect; //绘图区范围switch (message){case WM_CREATE: //创建窗口消息//return 0;break; //也可以case WM_PAINT://绘图函数,在窗口上绘图!hDC = BeginPaint(hwnd, &ps);//获得客户区大小GetClientRect(hwnd, &rect);//绘制字符串TextOut(hDC, 200, 200, TEXT("爱达人!"), lstrlen(TEXT("爱达人!")));//绘制椭圆图形Ellipse(hDC, 250, 250, 1200, 500);//绘制格式化文本,客户区中间垂直居中对齐DrawText(hDC, TEXT("我的第一个窗口程序!"), -1, &rect,DT_CENTER |DT_VCENTER | DT_SINGLELINE);EndPaint(hwnd, &ps);break;case WM_DESTROY://处理退出消息//绘制椭圆图形//Ellipse(hDC, 250, 250, 1200, 500);//测试PostQuitMessage(0);//此消息直接进入消息队列的头部!默认情况下,//DefWindowProc函数调用DestroyWindow函数来销毁窗口。
break;//default: //可以放在最后//return DefWindowProc(hwnd, message, wParam, lParam);}//return 0;//调用默认窗口过程以为应用程序未处理的任何窗口消息提供默认处理return DefWindowProc(hwnd, message, wParam, lParam);}*WM_DESTROY消息:窗口销毁后(调用DestroyWindow()后),消息队列添加WM_DESTROY消息。
流程:用户通过点击关闭程序按钮后,消息队列增加一条消息WM_CLOSE,然后程序从消息队列中取走WM_CLOSE,WM_CLOSE消息的默认处理方式为调用DestroyWindow()向窗口发送一个WM_DESTROY消息,消息队列增加WM_DESTROY,主程序消息循环再次取出后交给Windows系统,Windows系统调用窗口过程处理WM_DESTROY消息,处理方式为调用ostQuitMessage(),在消息队列中添加WM_QUIT标记,消息循环获取WM_QUIT后退出消息循环,程序退出。
如果窗口过程不处理WM_CLOSE消息,默认情况下,默认窗口过程DefWindowProc函数同样是调用DestroyWindow函数。
********************************************PostQuitMessage函数:向系统指示线程已请求终止(退出)。
通常用于响应WM_DESTROY消息。
void PostQuitMessage(int nExitCode //指定的退出码,是一个整数值。
这个退出码通常用来表示程序执行的结果或状态。
此值用作WM_QUIT消息的wParam参数。
);备注PostQuitMessage函数添加一个WM_QUIT退出标记到线程的消息队列并立即返回;这个函数只是向系统表明这个线程在将来的某个时候请求退出。
当线程从它的消息队列中检索WM_QUIT标记时,它应该退出它的消息循环并将控制权返回给系统。
返回到系统的退出值必须是WM_QUIT消息的wParam参数。
(有些书上将WM_QUIT视为一个消息,插入到消息队列头,然后立即退出,消息队列中剩余的消息不会被处理,虽然比较形象,但是不太严谨,WM_QUIT其实是一个退出标记。
)。
*/注意1.本例在关闭窗口后,终于可以正常退出程序了。
原因就在于窗口过程WndProc处理了WM_DESTROY消息,向窗口消息队列添加一个WM_QUIT退出标记。
消息循环GetMessage函数获取WM_QUIT后返回值为0,退出消息循环,进而退出进程。
2.动手实验:在WM_DESTROY消息处理模块添加一个绘制椭圆的函数:Ellipse(hDC, 250, 250, 1200, 500);编译器编译后提示:error C4700: 使用了未初始化的局部变量“hDC”。
错误原因:窗口过程中设置的hDC为局部变量,在WM_PAINT消息模块中使用,但是在WM_DETROY模块无法识别,说明局部变量在窗口过程中不可以跨消息模块使用,作用域仅限一个消息模块内。
记得水面以下的冰山部分并不是由我们实现的,Windows程序是消息驱动的程序。
解决方案:将变量定义为全局区的静态变量static HDC hDC;如果一个变量需要跨消息模块使用,请将其定义为static变量。
但是在这里并不建议将hDC定义为static变量,因为hDC会持续占用大块内存空间,随用随取就可以了。
在Ellipse函数处下断点,当关闭窗口后,执行Ellipse函数调用并不会显示窗口。
原因很简单,因为窗口已经不存在了。
2.2.8 第15练:处理WM_CLOSE消息#include <windows.h>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回调函数//窗口回调函数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){HDC hDC; //设备环境——绘图的地方PAINTSTRUCT ps; //绘图结构体变量RECT rect; //绘图区范围switch (message){case WM_CREATE: //创建窗口消息return 0;case WM_PAINT://绘图函数,在窗口上画画儿!hDC = BeginPaint(hwnd, &ps);//获得客户区大小GetClientRect(hwnd, &rect);//绘制字符串TextOut(hDC, 200, 200, TEXT("爱达人!"), lstrlen(TEXT("爱达人!")));//绘制椭圆图形Ellipse(hDC, 250, 250, 1200, 500);//绘制格式化文本,客户区中间垂直居中对齐DrawText(hDC, TEXT("我的第一个窗口程序!"), -1, &rect,DT_CENTER |DT_VCENTER | DT_SINGLELINE);EndPaint(hwnd, &ps);return 0;case WM_CLOSE:if (IDYES == MessageBox(hwnd,TEXT("是否真的要退出!),TEXT("OK?"),MB_YESNO)){DestroyWindow(hwnd);break;}elsebreak;//不退出,并且什么都没做。
case WM_DESTROY://处理退出消息PostQuitMessage(0);//此消息直接进入消息队列的头部!break;default: //可以放在最后return DefWindowProc(hwnd, message, wParam, lParam); //调用默认窗口过程以为应用程序未处理的任何窗口消息提供默认处理}return 0;//return DefWindowProc(hwnd, message, wParam, lParam); //调用默认窗口过程以为应用程序未处理的任何窗口消息提供默认处理}点击“关闭”系统菜单后,弹出对话框窗口,如图2-6所示:图2-6 WM_CLOSE消息注意读者可能会有疑问,当用户点击系统菜单“关闭”窗口时,是如何产生并获取WM_CLOSE消息的呢?答案是Windows操作系统获取“关闭”系统菜单消息后,再发送一个WM_CLOSE消息。
这个问题,我们将在下一节消息机制中详细讲解。
2.2.9 第16练:处理WM_SIZE消息#include <windows.h>LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //消息回调函数//窗口过程回调函数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){HDC hDC; //设备环境——绘图的地方PAINTSTRUCT ps; //绘图结构体变量RECT rect; //绘图区范围static int cxClient,cyClient;//客户区的宽度和高度,定义为静态局部变量switch (message){case WM_CREATE: //创建窗口消息//return 0;break; //也可以case WM_SIZE://更改窗口客户区大小的消息GetClientRect(hwnd, &rect);//等价于lParam参数的作用InvalidateRect(hwnd, &rect, TRUE);//TRUE重绘窗口客户区背景cxClient = LOWORd(lParam);//客户区的新宽度cyClient = HIWORd(lParam);//客户区的新高度break;case WM_PAINT://绘图函数,在窗口上画画儿!hDC = BeginPaint(hwnd, &ps);//获得客户区大小GetClientRect(hwnd, &rect);//绘制字符串---跟随客户区尺寸的变化而变化//TextOut(hDC, 200, 200, TEXT("爱达人!"), lstrlen(TEXT("爱达人!")));//对比测试TextOut(hDC, cxClient / 5, cyClient / 5, TEXT("爱达人!"),lstrlen(TEXT("爱达人!")));//绘制椭圆图形---跟随客户区尺寸的变化而变化//Ellipse(hDC, 250, 250, 1200, 500);//对比测试Ellipse(hDC, cxClient / 4 , cyClient / 4 , cxClient / 4 * 3,cyClient / 4 * 3);//绘制格式化文本,客户区中间垂直居中对齐DrawText(hDC, TEXT("我的第一个窗口程序!"), -1, &rect,DT_CENTER |DT_VCENTER | DT_SINGLELINE);EndPaint(hwnd, &ps);break;case WM_CLOSE:if (IDYES == MessageBox(hwnd,TEXT("是否真的要退出!"),TEXT("OK?"),MB_YESNO)){DestroyWindow(hwnd);break;}elsebreak;//不退出,并且什么都没做。
case WM_DESTROY://处理退出消息PostQuitMessage(0);//此消息直接进入消息队列的头部!break;default: //可以放在最后return DefWindowProc(hwnd, message, wParam, lParam);//调用默认窗口过程}return 0;//return DefWindowProc(hwnd, message, wParam, lParam); //调用默认窗口过程} 运行结果:图2-7 WM_SIZEE消息注意1.读者是否还记得,当我们执行ShowWindow函数时会向消息队列发送一个WM_SIZE消息。
WM_SIZE消息用于向窗口发送尺寸改变的消息。
当窗口的大小发生变化时,系统会生成并发送WM_SIZE消息给窗口,使程序能够对窗口尺寸的改变做出响应。
WM_SIZE消息的lParam 参数的高字部分是客户区的高,低字部分是客户区的宽。
wParam参数为请求的调整大小类型。
每个Windows消息都有附属的wParam参数和lParam 参数。
不同消息的wParam参数和lParam 参数的含义是不同的。
我们将在2.4节中详细讲解。
2.细心的读者会发现,本例中的窗口是可以通过鼠标拖动改变窗口的大小,同时窗口客户区绘制的图形和文本也随之而改变相应的位置。
请注意处理WM_PAINT消息时的GDI绘图函数,绘制图形和文本的坐标位置是和窗口客户区等比例的。
首先定义static变量cxClient,cyClient,接着在处理WM_SIZE消息时通过lParam参数获取窗口客户区的高和宽。
当然也可以通过GetClientRect函数获取窗口客户区的宽和高,使用其中一个方法就可以了。
3.请读者对比测试一下,如果将绘制文本和椭圆的坐标和区域设置为固定值,显示效果如何。

  • 收藏

分享给我的朋友们:

上一篇:设为主页、关闭窗口、加入收藏的方法汇总(主页如何显示收藏夹栏) 下一篇:[太原沐林装饰]新房装修预算不足怎么办?装修如何省钱呢?(太原沐林装饰)

一键免费领取报价清单 专享六大服务礼包

装修全程保障

免费户型设计+免费装修报价

已有312290人领取

关键字: 装修百科 装修咨询 装修预算表

发布招标得免费设计

申请装修立省30%

更多装修专区

点击排行