WINDOW PROGRAM DESIGN chapter 4(windows程序设计第四章)读书笔记

文本文件输出

WM_PAINT消息
Windows不会保留被遮住的窗口,当其他程序的窗口被移开时,Windows会要求程序重新绘制被遮住的客户去
Windows是一个消息驱动的系统,使用两种方式把各种事件通知给应用程序:

  1. 把消息放在消息队列中
  2. 向适当窗口直接发送消息
    Windows通过VM_PAINT消息来通知窗口过程其客户区需要重绘

进入消息循环前,调用的UpdateWindow函数,利用这个机会第一次发送VM_PAINT消息。此消息通知窗口过程重绘客户端。
以下事件发生时,窗口过程会收到一条VM_PAINT消息:

  1. 用户移动窗口,使原来被遮盖的部分显露出来
  2. 用户调节窗口大小
  3. 程序调用ScrollWindow或者ScrollDC函数滚动客户区
  4. 程序调用InvalidateRect或InvalidateRun函数显示生成WM_PAINT消息
    在某些情况下,当客户区的一部分被临时覆盖的时候,Windows会试图保存被覆盖的这部分,以便将来恢复时用。
  5. 鼠标指针在客户区移动
  6. 在客户区内拖动图标
    程序应该收集并保存所有用于绘制客户端的信息,但只在需要时才进行绘制——当收到WM_PAINT消息时

有效矩形和无效矩形
尽管窗口过程能够在收到VM_PAINT消息时更新整个客户区,但通常只更新一部分。需要被重新绘制的区域称为“无效区域”或“更新区域”
在客户区中有一个无效区域将导致Windows在应用程序的消息队列中放置一条WM_PAINT消息。
Windows内部为每一个窗口都保存了一个“绘制信息结构”。这个结构可以保存着一个可以覆盖该无效区域的最小矩形的坐标和一些其他的信息。注意,如果在窗口过程中处理一条等候处理的WM_PAINT消息之前,客户端中的另外一部分也失效了,那么Windows将计算出一个覆盖这两个失效部分的新的无效区域和无效矩形,并更新绘制信息结构中的数据。也就是说,Windows不会在消息队列中存放多条WM_PAINT消息

窗口过程可以通过调用InvalidateRect函数来强制使自己的客户区的一个矩形失效。如果消息队列中已经有一条VM_PAINT消息,Windows就会计算出一个新的无效矩形,如果没有,就…

窗口过程在处理VM_PAINT消息时,在调用BeginPaint函数后,整个客户区会变成有效的。程序也可以通过调用ValidateRect函数来使得客户区中任意矩形变得有效。如果该函数调用的结果是让整个无效区域都有效,那当前消息队列中的VM_PAINT就会被删除。

GDI简介
绘制一个窗口的客户区需要调用Windows的图形设备接口(GDI)函数。最常用的字符输出函数是TextOut:
TextOut (hdc, x, y, psText, iLength);
其向客户端输出一个字符串。参数psText是指向字符串的指针,而iLength是字符串的长度。参数x,y定义了字符串在客户区中的开始位置。hdc是一个设备环境句柄。这是GDI的一个重要部分,几乎所有GDI函数都要这个句柄作为函数的第一参数。

设备环境实际是GDI中的一个数据环境,其与特定的显示设备相关联。设备环境中的某些值是图形属性。决定GDI内部绘图函数的工作细节。例如在TextOut函数里,设备环境的属性决定着文本颜色,背景颜色,以及windows 用什么字体显示文本。
注意!程序在绘制前会获取一个设备环境句柄,在获取句柄后,Windows会在内部的设备环境结构中填入默认的属性值。
当程序完成了对客户区的绘制之后,它必须释放这个句柄。释放这个句柄之后,这个句柄不再有效!并且不能再被使用。程序必须在处理同一条消息的过程中获取和释放句柄。

一般有两种方式获取句柄
获取句柄的方式:此方法在处理VM_PAINT消息时可使用。涉及到两个函数:BeginPaint和EndPaint
这两个函数需要两个参数:窗口的句柄(窗口消息处理过程的参数),另一个是PAINTSTRUCT结构的变量的地址,此结构一般定义为:PAINTSTRUCT ps;
在处理WM_PAINT消息时,窗口过程先调用BeginPaint函数。这个函数会擦去无效区域的背景以便绘图。它还会同时填充ps结构的各个字段。其返回值就是设备的环境句柄,这环境句柄保存在hdc变量中,一般定义为:
HDC hdc;
此后,程序可以调用任何GDI函数了。
通常,处理VM_PAINT的消息代码如下:
case WM_PAINT:
hdc = BeginPaint (hand, &ps);
EndPaint (hwnd, &ps);
return 0;
窗口在处理VM_PAINT消息时必须成对调用BeginPaint和EndPaint。如果窗口过程不处理VM_PAINT消息,VM_PAINT消息就会被传递给Windows默认窗口过程DefWindowProc。在DefWindowProc中,WM_PAINT消息处理代码如下:
case WM_PAINT:
BeginPaint (hwnd, &ps);
EndPaint (hwnd, &ps);
return 0;

PAINTSTRUCT ps结构——绘制信息结构
当调用BeginPaint函数时,程序会自动完成对其中字段的填充。程序只能使用其中前三个值,其他供Windows内部使用。
typedef struct tagPAINTSTRUCT
{
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;
其中,fErase字段被设置为0,以为着Windows在先前的BeginPaint函数里已经擦出了无效区域的背景,
但是当程序通过调用InvalidateRect函数使客户区的一个矩形无效时,InvalidateRect函数的最后一个参数将指定背景是否要被擦除。如果参数是Flase(0),那Windows将不会擦除背景,同时在调用BeginPaint函数后,PAINTSTRUCT结构的fErase字段值将会是1

PAINTSTRUCT结构的rcPaint字段是一个RECT类型的结构。这就是无效矩形的边界。其不仅仅是一个无效矩形,也是剪裁的边界,意味着Windows将把绘制限制在这个矩形中。
以下的调用会将整个客户区无效化:在调用BeginPaint之前调用可以在该更新矩形之外绘制
InvalidateRect (hwnd, NULL, TRUE);

获取设备环境句柄的方法之二:处理非VM_PAINT消息时绘制客户端也是很重要的。调用GetDC函数来获取窗口客户区的设备环境句柄,在使用完后,使用ReleaseDC将其释放
hdc = GetDC (hwnd);
ReleaseDC (hwnd, hdc);
必须成对使用,在调用getdc后,退出窗口前要使用ReleaseDC。
不同于BeginPaint函数和,GETDC返回的设备环境句柄中的裁剪矩形是整个客户区,意味着你可以在客户区任何位置进行绘制,而不仅仅是在无效矩形里。与BeginPaint不同,GetDC不会将无效区域有效化。如果需要讲整个客户区有效化,可以这样调用函数:
ValidateRect (hwnd, NULL);

GetDC和ReleaseDC函数用于处理键盘消息或者鼠标消息。程序可以在收到用户的键盘或者鼠标输入时及时地绘制客户区,而不必生成VM_PAINT消息时进行绘制

发布了47 篇原创文章 · 获赞 10 · 访问量 1740

猜你喜欢

转载自blog.csdn.net/Antonio_Salieri/article/details/96381773