文本输出,取自《Windows程序设计》

 

综合使用

现在,我们似乎已经具备了在屏幕上显示多行文字所需要的所有知识。我们知道如何在WM_PAINT消息处理期间取得一个设备内容句柄,如何使用TextOut函数以及如何根据字符大小来安排字距,剩下的就是显示一点有意义的东西了。

前一章里,我们大概知道从Windows的GetSystemMetrics函数中取得的信息是很有意义的,该函数传回Windows中不同视觉组件的大小信息,如图标、光标、标题列和滚动条等。它们的大小因显示卡和驱动程序的不同而有所不同。GetSystemMetrics是在程序中完成与设备无关图形输出的重要函数。

该函数需要一个参数,叫做「索引」,在Windows表头文件定义了75个整数索引标识符(标识符的数量随着每个版本的Windows的发布而不断地增加,在Windows 1.0的程序写作者文件中仅列出了26个)。GetSystemMetrics传回一个整数,这个整数通常就是参数中指定的图形组件大小。

让我们来编写一个程序,显示一些可以从GetSystemMetrics呼叫中取得的信息,显示格式为每种视觉组件一行。如果我们建立一个表头文件,在表头文件中定义一个结构数组,此结构包含GetSystemMetrics索引对应的Windows表头文件标识符和呼叫所传回的每个值对应的字符串,这样处理起来要容易一些。表头文件名为SYSMETS.H,如程序4-1所示。

程序4-1 SYSMETS.H 
      
/*------------------------------------------------------------------
        
SYSMETS1.C -- System Metrics Display Program No. 1
        
                 (c) Charles Petzold, 1998
        
----------------------------------------------------------------*/
        
#include <windows.h>
        
#include "sysmets.h"
        
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
        
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
        
                 PSTR szCmdLine, int iCmdShow)
        
{
        
    static TCHAR szAppName[] = TEXT ("SysMets1") ;
        
    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 ("This program requires Windows NT!"),
        
                          szAppName, MB_ICONERROR) ;
        
  
        
    return 0 ;
        
    }
        
    hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 1"),
        
                   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 ;
        
     }
        

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        
{
        
    static int    cxChar, cxCaps, cyChar ;
        
    HDC                   hdc ;
        
    int                   i ;
        
    PAINTSTRUCT ps ;     
        
    TCHAR                szBuffer [10] ;
        
    TEXTMETRIC  tm ;
        

    switch (message)
        
    {
        
   case   WM_CREATE:
        
         hdc = GetDC (hwnd) ;
        

          GetTextMetrics (hdc, &tm) ;
        
          cxChar = tm.tmAveCharWidth ;
        
          cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
        
          cyChar = tm.tmHeight + tm.tmExternalLeading ;
        

          ReleaseDC (hwnd, hdc) ;
        
          return 0 ;
        

    case   WM_PAINT :
        
          hdc = BeginPaint (hwnd, &ps) ;
        

          for (i = 0 ; i < NUMLINES ; i++)
        
                  {
        
            TextOut       (hdc, 0, cyChar * i,                    
        
                         sysmetrics[i].szLabel,
        
                         lstrlen (sysmetrics[i].szLabel)) ;
        

            TextOut       (hdc, 22 * cxCaps, cyChar * i,    
        
                         sysmetrics[i].szDesc,
        
                         lstrlen (sysmetrics[i].szDesc)) ;
        

                   SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
        
        TextOut (hdc, 22 * cxCaps + 40 * cxChar, cyChar * i,   szBuffer,
        
    wsprintf (szBuffer, TEXT ("%5d"),
        
    GetSystemMetrics (sysmetrics[i].iIndex))) ;
        
              SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
        
         }
        
            EndPaint (hwnd, &ps) ;
        
            return 0 ;
        
    case   WM_DESTROY :
        
            PostQuitMessage (0) ;
        
    return 0 ;
        
    }
        
    return DefWindowProc (hwnd, message, wParam, lParam) ;
        
}
       

SYSMETS1.C窗口消息处理程序

SYSMETS1.C程序中的WndProc窗口消息处理程序处理三个消息:WM_CREATE、WM_PAINT和WM_DESTROY。WM_DESTROY消息的处理方法与第三章的HELLOWIN程序相同。

WM_CREATE消息是窗口消息处理程序接收到的第一个消息。在CreateWindow函数建立窗口时,Windows产生这个消息。在处理WM_CREATE消息时,SYSMETS1呼叫GetDC取得窗口的设备内容,并呼叫GetTextMetrics取得内定系统字体的文字大小。SYSMETS1将平均字符宽度保存在cxChar中,将字符的总高度(包括外部间距)保存在cyChar中。

SYSMETS1还将大写字母的平均宽度保存在静态变量cxCaps中。对于固定宽度的字体, cxCaps等于cxChar。对于可变宽度字体,cxCaps设定为cxChar乘以150%。对于可变宽度字体,TEXTMETRIC结构中的tmPitchAndFamily字段的低位为1,对于固定宽度字体,该值为0。 SYSMETS1使用这个位从cxChar计算cxCaps:

cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
        

SYSMETS1在处理WM_PAINT消息处理期间完成所有窗口建立工作。通常,窗口消息处理程序先呼叫BeginPaint取得设备内容句柄,然后用一道for叙述对SYSMETS.H中定义的sysmetrics结构的每一行进行循环。三列文字用三个TextOut函数显示,对于每一列,TextOut的第三个参数都设定为:

cyChar * i
        

这个参数指示了字符串顶端相对于显示区域顶部的图素位置。

第一条TextOut叙述在第一列显示了大写标识符。TextOut的第二个参数是0,这是说文字从显示区域的左边缘开始。文字的内容来自sysmetrics结构的szLabel字段。我使用Windows函数lstrlen来计算字符串的长度,它是TextOut需要的最后一个参数。

第二条TextOut叙述显示了对系统尺寸值的描述。这些描述存放在sysmetrics结构的szDesc字段中。在这种情况下,TextOut的第二个参数设定为:

22 * cxCaps
        

第一列显示的最长的大写标识符有20个字符,因此第二列必须在第一列文字开头向右20 × cxCaps处开始。我使用22,以在两列之间加一点多余的空间。

第三条TextOut叙述显示从GetSystemMetrics函数取得的数值。变宽字体使得格式化向右对齐的数值有些棘手。从0到9的数字具有相同的宽度,但是这个宽度比空格宽度大。数值可以比一个数字宽,所以不同的数值应该从不同的横向位置开始。

那么,如果我们指定字符串结束的图素位置,而不是指定字符串的开始位置,以此向右对齐数值,是否会容易一些呢?用SetTextAlign函数就可以做到这一点。在SYSMETS1呼叫:

SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
        

之后,传给后续TextOut函数的坐标将指定字符串的右上角,而不是左上角。

显示列数的TextOut函数的第二个参数设定为:

22 * cxCaps + 40 * cxChar
        

值40*cxChar包含了第二列的宽度和第三列的宽度。在TextOut函数之后,另一个对SetTextAlign的呼叫将对齐方式设定回普通方式,以进行下次循环。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值