首页 > 学院 > 开发设计 > 正文

Windows编程基础 - 文本显示

2019-11-17 05:18:31
字体:
来源:转载
供稿:网友

  前一章所介绍的程序只创建了一个的窗口,但是除了窗口的标题栏中显示的窗口名之外,并未用它显示其它信息。应用程序可以在窗口的用户区内显示文本和图形信息。本章仅讨论文本行的显示。通过本章的程序实例,我们将介绍几个用于文本输出的Windows函数以及有效和无效矩形区的概念。同时介绍有关设备对象和字体尺寸的基本概念。这里,我们还将介绍几个重要的Windows消息。应用程序可以利用这些消息进行程序的初始化和终止处理,以及完成应用程序的任务等。

2.1、显示信息
  下面的程序从用户区的左上角开始显示“Hello,Welcome to Windows”。

  // 2-1.c 显示信息
  #include <windows.h>

  LRESULT CALLBACK WndPRoc(HWND, UINT, WPARAM, LPARAM);

  int PASCAL WinMain(
    HINSTANCE hInstance,   // 应用程序的实例句柄
    HINSTANCE hPrevInstance, // 该应用程序前一个实例的句柄
    LPSTR lpszCmdLine,    // 命令行参数串
    int nCmdShow )      // 程序在初始化时如何显示窗口
  {
     char szAppName[] = "DispText";
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;

    if (!hPrevInstance) {
      // 该实例是程序的第一个实例,注册窗口类
      wndclass.style = CS_VREDRAW CS_HREDRAW;
      wndclass.lpfnWndProc = WndProc;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
      wndclass.hInstance = hInstance;
      wndclass.hIcon = LoadIcon(hInstance, IDI_application);
      wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.lpszClassName = szAppName;

      if (!RegisterClass(&wndclass))
        // 假如注册失败
        return FALSE;
    }

    // 对每个实例,创建一个窗口对象
    hwnd = CreateWindow(
      szAppName,
      "Display Text",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL );

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while(GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    return msg.wParam;
  }

  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    char msg[] = "Hello, Welcome to Windows!";
    PAINTSTRUCT ps;
    HDC hDC;

    switch(message)
    {
      case WM_PAINT:
        hDC = BeginPaint(hwnd, &ps);
        TextOut (hDC, 0, 0, msg, sizeof(msg) - 1);
        EndPaint(hwnd, &ps);
        return 0;

      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  我们首先介绍这个程序中使用的Windows数据类型,然后介绍和这几个类型有的Windows函数,最后介绍消息WM_PAINT的含义。
  HDC是在Windows.h中定义的一个数据类型,类似于HWND,它是用于标识一个设备对象的句柄;许多绘图函数需要这个句柄,这些绘图函数在这个句柄标识的对象上绘图。
  PAINTSTRUCT结构类型的变量所包含的信息可被用来重新绘制窗口的用户区域,下面的定义中只给出应用程序关心的几个域,其它未列出的域是供Windows系统使用的。

  typedef struct tagPAINTSTRUCT {
    HDC hdc;   // 标识显示设备对象的句柄
    BOOL fErase; // 若为非零。说明用户背景已被重画过,否则未被重画
    RECT rcPaint; // 指定要求重画(着色)的矩形区域的左上角和右下角坐标
    //......
  } PAINTSTRUCT;

  其中,类型RECT的说明为:

  typedef struct tagRECT {
    int left;  // 矩形左上角的X坐标值
    int top;   // 矩形左上角的Y坐标值
    int right;  // 矩形右上角的X坐标值
    int bottom; // 矩形右上角的Y坐标值
  } RECT;

  函数BeginPaint()使用一个窗口句柄和一个指向PAINTSTRUCT类型的变量的指针为参数,它除了填充该指针所指向的变量的各域以外,同时向Windows借用一个显示设备用于绘制用户区。该函数返回这个设备对象的句柄,有了该句柄,应用程序就可以随意绘制用户区。函数EndPaint()与函数BeginPaint()所使用的参数一样,它必须与函数BeginPaint()配对使用,并且必须同时都用在WM_PAINT消息内。函数EndPaint()有两个作用。其一是归还BeginPaint()所借用的显示设备对象。Windows治理着五个公用的显示设备对象,供给用程序在显示设备上进行文本和图形输出所用。当一个窗口对象要绘制它的用户区时,它必须首先向Windows借用一个显示设备对象。由于公用的显示设备对象有限,因此,窗口对象在绘制完它的用户区之后,必须及时归还它所借用的设备对象,以不影响其它对象使用公用显示设备对象。一般的原则是:在从窗口函数中返回之前,应归还所借用的显示设备对象。EndPaint()函数的第二个作用是消除应用程序消息队列中的WM_PAINT消息,关于WM_PAINT消息,我们放在后面单独讨论。
  函数TextOut()使用BeginPaint()所借用的显示设备对象,在用户区中显示一条消息。表2-1给出该函数的使用说明。

  表2-1 TextOut 函数
用 途该函数用当前选择的字体绘制一字符串。其中参数x和y是串中第一个字符左上角的坐标。原 型BOOL TextOut(   HDC hDC 设备对象的句柄  int x,串起始点的逻辑x坐标值(相对于用户区左上角)   int y,串起始点的逻辑y坐标值(相对于用户区左上角)   LPSTR lpString, 所要绘制的字符串  int nCount 所要绘制的字符个数); 返回值返回非零,则串被绘制,否则没有被绘制。注:关于逻辑坐标的含义在第三章讨论。

 2.2、绘制和重画用户区
  你试着运行上节给出的程序。当该应用程序的窗口出现在屏幕上时,观察窗口中显示的信息。然后使用鼠标(或键盘)移动该窗口;将窗口隐藏在其它窗口后面,再让它显现出来;使窗口以最小化方式显示,再恢复为原窗口大小。在对该窗口对象进行上述操作之后,观察用户区显示的信息有什么变化。
  上述操作并没有改变(也未破坏)用户区中显示的信息,为什么呢?要回答这个问题,必须首先明白消息WM_PAINT的作用。
  Windows是一种消息驱动的系统。通过把消息邮寄到应用程序的队列中(甚至于直接发送到有关的窗口对象上),Windows通知应用程序所发生的各种有关事件。当Windows认为(由于窗口用户区的某些部分显示的内容受到破坏)需要窗口对象重新绘制用户区时,Windows就在应用程序的消息队列中放置一条WM_PAINT消息,窗口对象在接受到WM_PAINT消息之后,就重新绘制它的用户区中所显示的内容。
  在前面一章我们曾介绍了Windows应用程序的面向对象的特点,面向对象的方法将对象视为能作出动作。因此,当一个对象(例如Windows)需要另一个对象作某件事时,就向它发送相应的消息,让它动作起来。绘制对象的用户区是对象自己的事,所以,当一个对象的用户区需要重绘时,Windows就向这个对象发送WM_PAINT消息。Windows知道在什么情况下需要窗口对象重绘其用户区。

2.3、有效和无效矩形区
  当Windows通知窗口对象重绘用户区时,并非整个用户区都要重绘。例如,当一个覆盖了窗口用户区域的对话框消失时,只有被对话框覆盖的用户区需要重新绘制(被对话框覆盖的其它区域,例如标题栏、滚动杠等重绘问题由函数DefWindowProc负责。Windows向窗口对象发送WM_NCPAINT消息;窗口对象将这个消息交给DefWindowProc函数进行缺省处理;DefWindowProc绘制窗口对象的非用户区)。这个需要重绘的区域称为“无效矩形区”。如图2-1所示。在任何情况下,Windows通知窗口对象需要重绘的区域总是一个矩形区域。在用户区中出现的一个无效矩形提示Windows在应用程序的消息队列中放置WM_PAINT消息,窗口对象仅在其用户区无效接收到WM_PAINT消息。

Windows编程基础 - 文本显示(图一)图2-1 窗口用户区的无效矩形区
  各种排队的消息首先在应用程序的消息队列中按优先级排队,WM_PAINT有最低的优先别,它总是在队列中的其它消息都被处理完之后才被处理。因此,在应用程序处理其他消息时,有可能又出现新的无效矩形,这样Windows又要向消息队列中放置WM_PAINT消息。
  但是,Windows只为每个窗口对象保留一条WM_PAINT消息和一个“绘制信息结果” — PAINTSTRUCT,这个结构内包含有无效矩形区的坐标。当一个窗口对象出现新的无效矩形区时,Windows在向应用程序的消息队列中放置WM_PAINT消息之前,它首先检查在消息队列中是否已存在一条预备发送给该窗口对象的WM_PAINT消息。若该消息存在,Windows将这两条WM_PAINT消息合并为一条WM_PAINT消息。该消息的“绘制信息结构”的无效矩形区将包含原来的两个WM_PAINT消息的无效矩形区。
  在窗口对象处理WM_PAINT消息时,通过函数BeginPaint可以获得无效矩形区的坐标。在其他情况下,只能通过调用函数GetUpdateRect()获得无效矩形区的坐标(见表2-2)

  表2-2 GetUpdateRect 函数
用 途检索无效矩形区的坐标,假如该矩为空,则所有坐标值为零。原 型GetUpdateRect(   HWND hWnd, 和用户区相关联的窗口对象的句柄  LPRECT lpRect, 指向类型为RECT的变量的指针,该变量用于保存所获得的无效矩形区的坐标(相对于用户区左上角的坐标)   BOOL bErase所要绘制的字符个数); 返回值假如更新区不空,返回非零,否则返回零。
  无效矩形也是一个裁剪矩形,也就是说,Windows限制应用程序只能在这个区域中绘图。当使用PAINSTRUCT结构中的显示设备对象绘图时,Windows将裁剪掉在rcPaint域所标识的矩形之外所绘的图。
  应用程序可以使用函数InvalidateRect()产生一个的无效矩形。表2-3给出了函数InvalidateRect()和函数ValidateRect()的使用说明。

  表2-3-1 InvalidateRect() 函数
用 途将该函数所指定的一个矩形作为无效矩形区加到窗口的无效矩形区上。原 型VOID InvalidateRect(   HWND hWnd, 和无效矩形区相关联的窗口的句柄  LPRECT lpRect, 指向RECT类型的变量的指针,该变量定义的矩形被加到无效矩形区上,假如该指针为NULL,则整个用户区变为无效矩形区   BOOL bErase是(非零)否(零)擦除lpRect所标识的区域的内容); 注 释当该函数被调用时,它生成一条WM_PAINT消息,该消息所附带的无效矩形区由lpRect指定。Windows将该消息和应用程序信息队列中已存在的一条WM_PAINT消息合并。
  表2-3-2 ValidateRect() 函数
用 途使无效矩形区有效。原 型VOID ValidateRect(   HWND hWnd, 窗口句柄  LPRECT lpRect, 指向RECT类型的变量的指针,无效矩形区将不再包含由该变量所指定的矩形区域,假如其值为NULL,则整个用户区有效 ); 注 释函数BeginPaint()自动使整个用户区有效。

  进行裁剪操作是费时间的,为了提高程序的运行效率,当用户区显示的内容不很复杂时(或可以很有效地重画整个用户区时),可以在调用BeginPaint()函数之前调用InvalidateRect函数使整个用户区无效,然后,应用程序在整个用户区上进行绘制。
  由于WM_PAINT消息的优先级很低,这样,由于窗口对象不能及时收到WM_PAINT消息而影响用户对屏幕对象的视觉感觉。为弥补这个缺陷,程序员可以考虑使用函数UpdateWindows(),它在应用程序的消息队列中存在WM_PAINT消息的情况下,强使Windows立即向窗口对象发送WM_PAINT消息。例如,前面几个示例程序的WinMain函数中,我们多次使用了这个函数。这样,程序一启动,用户可以很快在屏幕上看到窗口。
  EndPaint不仅归还显示设备对象,同时,它还清除应用程序的消息队列中的WM_PAINT消息。当使用函数ValidateRect使用窗口对象不存在任何无效的矩形区域时,ValidateRect函数同样也清除消息队列中的WM_PAINT消息。

2.4、格式化显示信息
  本节介绍另一个绘制字符的函数DrawText(),表2-4给出了该函数的使用说明。

  // 2-4-1.c
  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    HDC hDC;
    PAINTSTRUCT ps;
    RECT rect;

    switch(message)
    {
      case WM_PAINT:
        hDC = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        DrawText(hDC, "Hello, Welcome to Windows!", -1,
             &rect, DT_SINGLELINE DT_CENTER DT_VCENTER);
        EndPaint(hwnd, &ps);
        return 0L;

      case WM_DESTROY:
        PostQuitMessage(0);
        return 0L;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  该程序在用户区的中心显示一条信息,用户试着移动屏幕上窗口的位置,或改变窗口的大小,信息始终显示在中心位置。该程序有助于你更好地理解WM_PAINT消息的作用。
  程序中使用了函数GetClientRect(),它将用户区的坐标(左上角和右下角,其中左上角坐标总为(0,0),而右下角坐标是相对于用户区左上角坐标)拷贝到第二个指针参数所向的RECT类型的变量。 三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案

  表2-4 DrawText 函数
用 途该函数在lpRect参数指定的矩形中格式化文本。原 型int DrawText(   HDC hDC 设备对象句柄  LPSTR lpString, 指向要绘制的字符串  int nCount 要绘制的字符个数。若其为-1,则lpString必须指向以空字符(即‘/0’)结尾的字符串  LPRECT lpRect 指向一个RECT类型的变量,在该变量所指定矩形内进行文本的格式化(矩形以逻辑坐标表示,见第三章)  Word wFormat以下列常量使用“位或”运算得到的值(表2-4-1));  返回值返回本文的高度。
  表2-4-1 wFormat 值 类型说明DT_BOTTOM与DT_SINGLELINE组合使用,指定底对齐DT_CENTER文本水平居中DT_VCENTER垂直对中文本(与DT_SINGLELINE组合使用)DT_LEFT文本左对齐DT_RIGHT文本右对齐DT_TOP顶对齐(与DT_SINGLELINE组合使用)DT_SINGLELINE绘制在一行中。回车换行符不打断该行
  上面的程序有一个小问题,窗口对象每当收到WM_PAINT消息时都要调用函数GetClientRect()来获得用户区的大小。这样,对程序的效率有些影响,因为窗口对象在大多数情况下收到WM_PAINT消息时,用户区的大小(或说整个窗口的大小)并没有改变,例如,在窗口被对话框覆盖的情况下等。
  每当窗口的大小发生变化时,Windows都要向窗口对象直接发送一条WM_SIZE消息(不通过应用程序的消息队列),消息的lParam参数的低位字中含有用户区的宽度,而高位字中含有用户区的高度,并使用设备单位(像素)表示(有关设备单位的内容在第三章介绍)。在Windows.h中定义的宏LOWORD和HIWORD可用来分离参数lParam的高位字和低位字。下面是使用WM_SIZE消息重新设计的程序。

  // 2-4-2.c
  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    HDC hDC;
    PAINTSTRUCT ps;
    static RECT rect;

    switch(message)
    {
      case WM_SIZE:
        rect.right = LOWORD(lParam);
        rect.bottom = HIWORD(lParam);
        return 0L;

      case WM_PAINT:
        hDC = BeginPaint(hwnd, &ps);
        GetClientRect(hwnd, &rect);
        DrawText(hDC, "Hello, Welcome to Windows!", -1,
             &rect, DT_SINGLELINE DT_CENTER DT_VCENTER);
        EndPaint(hwnd, &ps);
        return 0L;

      case WM_DESTROY:
        PostQuitMessage(0);
        return 0L;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  注重,由于处理消息WM_SIZE的代码所预备的数据是提供其它消息(WM_PAINT)使用的,它们只有在窗口函数再次被进入时才能被使用,因此,变量rect被说明为静态变量。当在不同的消息之间共享一些数据时,必须注重使用静态生存期的变量。
  当调用ShowWindow()函数时(例如,第一章中程序中的主函数),Windows也要使用WM_SIZE消息调用窗口函数,因为这时窗口第一次被显现出来。

2.5、字体的大小与多行信息显示
  虽然DrawText()函数也可以显示多行信息,但在显示多行信息时, 经常使用的是函数TextOut()。为了显示多行信息,我们必须了解显示设备对象度量字体尺寸的方法,因此,本节先介绍这方面的内容。在本节给出的程序示例中,我们还要介绍WM_CREATE消息和借用显示设备对象的另一种方法。
  字样是一种基本的字符图案,具有特定的的衬线和笔划宽度,而字体指的是具有相同字样和尺寸的字符集。字体的尺寸用点来度量,点是印刷业中使用的度量字体的最小度量单位,每一英寸大约有72个点。有关字体的更具体的内容在以后章节介绍。
  应用程序可以使用Windows提供的不同字体,也可以使用在应用程序的可执行文件中定义和包含的专用字体。本节仅介绍应用程序如何获得有关字体尺寸方面的信息。使用TextOut函数显示多行文本时,需要确定字体字符的大小,以便根据字符的高度和宽度在用户区中显示多行文本。根据字符的高度可以在文本的相继行之间留出空距,而根据字符的宽度在文本的各列之间留出空距。
  结构类型TEXTMETRIC描述了与一种字体有关的基本信息,它的各域所给出的字体大小以逻辑单位表示(关于逻辑单位的介绍参见下一章)。该结构类型包含有许多域,图2-2给出了与字体垂直尺寸有关的五个域的定义。

Windows编程基础 - 文本显示(图二)图2-1 TEXTMETRIC结构类型中定义垂直尺寸字体的域
  tmInternalLeading的值是答应在一个字符上加上重音号的空隙量,tmExternalLeading的值是字体的设计者推荐的空隙量,在显示多行文本时程序员可以拒绝使用这个空隙量。
  在TEXTMETRIC结构类型中,有两个域用来定义字符的宽度:tmAveCharWidth表示字体字符的平均宽度,tmMaxCharWidth表示字体最宽的字符的宽度。Windows中使用两种类型的字体,一类是固定宽度的字体,固定宽度的字体的每个字符的宽度是一样的,这样tmAveCharWidth和tmMaxCharWidth两值相等;另一类是可变宽度的字体,对于这类字体,每个字符占用的宽度不一样。例如, 字符“w”和“i”的宽度就不同,使用可变宽度的字体可以绘制紧凑的文本。
  可以使用函数GetTextExtent计算出一个特定的文本行的宽度和高度,使用函数GetTextMetrics可以得到字符的有关尺寸,这两个函数的说明见表2-5。

  表2-5-1 GetTextExtent 函数
用 途该函数使用设备对象当前使用的字体计算一个文本行宽度和高度(逻辑单位),在计算时不考虑当前裁剪区。原 型DWORD GetTextExtent(   HDC hDC 设备对象句柄  LPSTR lpString, 指向一个字符串  int nCount 所要计算字符数。);  返回值返回字符串的尺寸,高度在高位字上,宽度在低位字上。
  表2-5-2 GetTextMetrics 函数
用 途返回设备对象当前所使用的字体字符的有关尺寸。原 型DWORD GetTextMetrics(   HDC hDC 设备对象句柄  LPTEXTMETRIC lpMetric, 指向TEXTMETRIC类型的变量的指针,有关尺寸被放入该变量中。);  返回值若调用成功,返回非零,否则返回零。

  三层交换技术 交换机与路由器密码恢复 交换机的选购 路由器设置专题 路由故障处理手册 数字化校园网解决方案  下面的程序使用所介绍的这些知识在用户区中显示多行文本。
  
  // 2-5.c
  #include <windows.h>
  #include <stdio.h>

  LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

  int PASCAL WinMain(
    HINSTANCE hInstance,   // 应用程序的实例句柄
    HINSTANCE hPrevInstance, // 该应用程序前一个实例的句柄
    LPSTR lpszCmdLine,    // 命令行参数串
    int nCmdShow )      // 程序在初始化时如何显示窗口
  {
     char szAppName[] = "DispText";
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;

    if (!hPrevInstance) {
      // 该实例是程序的第一个实例,注册窗口类
      wndclass.style = CS_VREDRAW CS_HREDRAW;
      wndclass.lpfnWndProc = WndProc;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
      wndclass.hInstance = hInstance;
      wndclass.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
      wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
      wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.lpszClassName = szAppName;

      if (!RegisterClass(&wndclass))
        // 假如注册失败
        return FALSE;
    }

    // 对每个实例,创建一个窗口对象
    hwnd = CreateWindow(
      szAppName,
      "Display Text",
      WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT, CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL );

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while( GetMessage(&msg, NULL, 0, 0)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }

    return msg.wParam;
  }

  LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  {
    static int xChar, yChar;
    char szBuffer[256];
    int line;
    HDC hDC;
    PAINTSTRUCT ps;
    TEXTMETRIC tm;
    FILE *fp;

    switch(message)
    {
      case WM_CREATE:
        hDC = GetDC(hwnd);
        GetTextMetric(hDC, &tm);
        xChar = tm.tmAveCharWidth;
        yChar = tm.tmHeight + tm.tmExternalLeading;
        ReleaseDC(hwnd, hDC);
        return 0L;

      case WM_PAINT:
        hDC = BeginPaint(hwnd, &ps);
        line = 0;
        if((fp = fopen("disptext.cpp", "r")) != NULL)
        {
          while(!feof(fp)) {
            int i = 0;
            char ch;
            while((ch = fgetc(fp)) != '/n' && ch != EOF)
              szBuffer[i++] = (char)ch;
            TextOut(hDC, xChar, line*yChar, szBuffer, i);
            line++;
          }
          fclose(fp);
        }
        EndPaint(hwnd, &ps);
        return 0L;

      case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
  }

  该程序运行后,在用户区中将显示本程序的部分内容。
  当窗口对象被第一次创建时(调用函数CreateWindow()),Windows向窗口对象发送消息WM_CREAT,这是窗口对象接收的第一个(对应用程序有意义的)消息,我们一般使用这条消息进行与本窗口对象有关的初始化工作。例如,在本程序示例中,我们用于计算字符的宽度和高度(包括了空隙量)。由于使用函数GetTextMetric()需要一个设备对象句柄,我们使用函数GetDC()从Windows那里借用一个公用显示对象。
  Windows只有有限的五个公用的显示设备对象供正在运行的所有的应用程序使用,这些显示设备对象是Windows的一个宝贵的资源,当一个窗口对象不再使用通过函数GetDC()借用的显示设备对象时,应使用函数ReleaseDC()将它归还给Windows,否则,其它窗口对象将由于不能借用到显示设备对象而不能绘制它的用户区。因此,函数GetDC()和ReleaseDC()要配合使用,当窗口对象使用GetDC借用了一个显示设备对象之后,在从窗口函数返回之前,应使用ReleaseDC函数归还所借用的显示设备对象。
  函数GetDC/ReleaseDC用于在处理非WM_PAINT消息其间需要显示设备对象进行绘制时。在处理WM_PAINT消息其间应使用函数BeginPaint/EndPaint,因为使用GetDC/ReleaseDC不能清除应用程序的消息队列中的WM_PAINT消息。假如WM_PAINT消息不能被清除,则窗口对象会不断地接收到WM_PAINT消息。
  设备对象总定义有一个裁剪区,使用函数GetDC()得到的设备对象将整个用户区作为裁剪区,因此,使用该设备对象所做的绘图不会出现在用户区之外。

2.6、小结
  本章介绍了在用户区中显示信息的有关问题,同时介绍了消息WM_CREATE、WM_SIZE和WM_PAINT的意义和用途。WM_CREATE是在建立窗口对象时Windows发送给窗口对象的第一条对应用程序有意义的消息,我们可以利用这条消息进行程序的初始化工作。窗口对象接收到最后一条对应用程序有意义的消息是WM_DESTROY消息,我们可以使用这条消息完成一些程序终止之前的清除工作,例如释放内存对象等。根据应用程序的使用要求,利用其它消息完成一些别的处理工作,例如响应用户的输入操作和命令等。
  WM_PAINT消息是一条非常重要的消息,它的作用是通知窗口对象用户区显示的内容已被破坏,需要重绘。虽然在处理任何消息时都可以绘制用户区,但将用户区的绘制工作集中于处理WM_PAINT消息的程序段中是合理的,这可以保证用户区中总显示出合适的内容。学习Windows程序设计,重要的内容之一是把握Windows函数的功用和使用方法,但更重要的是把握一条消息是怎么样产生的,窗口对象利用这条消息能做什么工作。

  Windows编程基础 - 文本显示(图三) 本章节附带的例程(4KB)


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表