windows程序设计第三章-Windows和消息
A Windows of One's Own
很简单,CreateWindow即可。等等,该函数的第一个参数怎么是window class name,这个窗口类又要有一个什么window procedure?
Architectural概论
windows(窗口)是个object(对象)。 child windows(control windows):push buttons,radio buttons,check boxes.....
如何理解message呢,我们已经习惯调用操作系统的函数,但操作系统也可以调用应用程序的函数。当windows响应某一事件时,会通过调用相应的procedure代码,把message发送给程序。procedure代码要么是程序的一个函数,要么位于dll中。procedure根据消息完成一些操作,并将控制权交还给windows.
窗口是基于窗口类创建的。后者规定了处理消息的窗口过程,可实例化多个窗口。 当windows程序运行时,Windows创建消息队列。有些消息存于队列,以待在windows的message loop中被抓取并dispatch,也有一些消息会直接送入窗口过程,而不进入消息队列。
HELLOWIN程序
#include <Windows.h> LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,PSTR szCmdLine,int iCmdShow) { static TCHAR szAppName[] = TEXT("HelloWin"); 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("fail!"),szAppName,MB_ICONERROR); return 0; } hwnd = CreateWindow(szAppName, TEXT("The hello program"), 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; // return 0; } //WParam是int,LPARAM是long LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; RECT rect; switch(message) { case WM_CREATE: PlaySound(TEXT("D:\\Windows XP 启动.wav"),NULL,SND_FILENAME | SND_ASYNC); return 0; case WM_PAINT: hdc = BeginPaint(hwnd,&ps); GetClientRect(hwnd,&rect); DrawText(hdc,TEXT("Hello,高峰"),-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER); EndPaint(hwnd,&ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd,message,wParam,lParam); }
程序截图如下
客户区是指程序可draw的区域,通常位于边框和标题栏之间。
Thinking Globally
上面的windows基本框架以后可照搬。
windows函数调用
上面的程序包含了18个win函数调用,不解释先。
大写的标识符
其实都是些常数,其前缀有一定的意义,它们的定义都在头文件中可以查看。
新的数据类型
主要是MSG,WINDCLASS,PAINTSTRUCT和RECT
获得各种Handle
HINSTANCE, HWND, HDC(设备上下文的句柄),所谓句柄,就是一个和某一个对象联系起来的32位数字。依靠句柄,可在windows函数之间访问对象。
匈牙利命名法
变量名同时表征变量类型和变量意义。
Registering 窗口类
最重要的两个域为第二个lpfnWndProc和最后一个,前者指定窗口过程函数,后者指定窗口类名。
创建窗口
使用CreateWindow函数,返回hwnd(HWND类型,窗口句柄)
显示窗口
创建窗口后,窗口的信息位于内存,还没有显示在video display上。需调用ShowWindow将窗口在屏幕上显示。如ShowWindow的第二个参数为SW_SHOWNORMAL,则窗口的客户区将被擦拭。而调用UpdateWindow可导致客户区重绘(发送了WM_PAINT消息)。
消息循环
GetMessage函数抓取消息,除了抓取WM_QUIT消息会返回0终止循环之外,其他消息都返回非零数。
TranslateMessage(&msg);将做一些键盘消息转换(详情见第六章)。DispatchMessage(&msg);将消息返回给windows,windows再将其发送给适当的窗口过程进行处理。这意味着是windows调用了窗口过程函数WndProc,当WndProc处理完后,将控制权交还给windows,即回到DispatchMessage调用后,接着继续消息循环。
窗口过程
每个窗口过程函数都对应于一个窗口类。窗口过程一般由windows调用,但程序中也可通过SendMessage间接调用程序中的窗口过程。
处理消息
在switch中没处理的消息,应调用DefWindowProc。
播放声音文件
WM_CREATE是在CreateWindow函数中被直接作为消息参数,调用了窗口过程。使用PlaySound时,异步播放,这样当声音响起后,即返回到调用方,以继续下面的初始化。
WM_PAINT消息
当客户区invalid必须要update时,将发送此消息。
client区何时会invalid呢?当窗口初创时,整个client区都是invalid的,当调用UpdateWindow时,第一个WM_PAINT消息就这样产生了。当resize时,整个client区也会invalid,此时窗口过程也会收到WM_PAINT.当最小化后再次还原时,也会发送WM_PAINT。
当窗口间互相重叠时,重叠部分被移开时,该部分invalid,也会发送WM_PAINT,但只重绘invalid部分。
在BeginPaint中,如果client区背景还未擦掉,windows擦掉其背景。BeginPaint将使整个client区validated,它将返回一个device context的句柄,用以绘图。EndPaint用以释放DC句柄。
GetClientRect中,left,top都是0,right,bottom反映客户区的长宽。
WM_DESTROY消息
用户点关闭按钮或点击系统菜单中的关闭命令时发送该消息。如果不在窗口过程中处理该消息,窗口是会被关掉,但程序没法终结。
windows编程的麻烦
几乎所有windows程序都在窗口过程中对消息做出响应,这是windows编程的大部分工作。在winMain中,不过就是窗口类注册,创建窗口,从消息队列取出并发送消息等事。
Don’t call me ,i’ll call you
在windows程序中,windows总是会调用你的程序,特别是窗口过程。
Queued and Nonqueued Messages
queued messages:放入消息队列。nonqueued消息,直接是windows调用某些函数的结果,并提供参数给WndProc的调用。
Get In and Out Fast
若处理某个消息耗时很长,20章有解决办法。
posted on 2010-05-09 05:51 speedmancs 阅读(453) 评论(0) 编辑 收藏 举报