文章结构说明:
- 本文是要说明什么
- 关键代码解释和说明
- 上机实践的工程源码和提示
一、文章概要
在VC6.0编译环境用C加载显示多行的文本文件。主要是参考:http://www.bccn.net/Article/kfyy/cjj/jszl/200412/430.html
重点主要是windows中字体结构信息的学习,以及如何计算字符的宽度高度,如何排列加载的字符和文字完成多行显示。原理也很简单,得到当前设备的字符高度,第一行的起点在(0,0),第二行就是(0,字符高度),第三行就是(0,字符高度*2)等等。然后调用函数在这些位置显示字符即可。
二、代码说明
这里解释下WM_CREATE消息处理函数的代码:
1 case WM_CREATE: 2 hdc = GetDC(hWnd);//从OS借用设备 3 GetTextMetrics(hdc, &tm);//获取显示设备上下文 4 xChar = tm.tmAveCharWidth;//设备的字符平均宽度 5 yChar = tm.tmHeight + tm.tmExternalLeading;//设备的字符高度 6 ReleaseDC(hWnd, hdc);//释放设备 7 break;
GetDC()函数的MSDN(VC6.0版)解释如下:
The GetDC function retrieves a handle to a display device context (DC) for the client area of a specified window or for the entire screen. You can use the returned handle in subsequent GDI functions to draw in the DC.
即返回一个显示设备上下文句柄。
GetTextMetrics()函数MSDN:
The GetTextMetrics function fills the specified buffer with the metrics for the currently selected font.
即从第一个参数——hdc显示设备上下文——中获得的一种字体有关的基本信息填入到第二个参数——tm描述字体信息的结构类型TEXTMETRIC变量中去。
TEXTMETRIC结构:
结构类型TEXTMETRIC描述了与一种字体有关的基本信息,它的各域所给出的字体大小以逻辑单位表示(关于逻辑单位的介绍参见下一章)。该结构类型包含有许多域,图2-2给出了与字体垂直尺寸有关的五个域的定义。
图2-1 TEXTMETRIC结构类型中定义垂直尺寸字体的域 |
tmInternalLeading的值是允许在一个字符上加上重音号的空隙量,tmExternalLeading的值是字体的设计者推荐的空隙量,在显示多行文本时程序员可以拒绝使用这个空隙量。
在TEXTMETRIC结构类型中,有两个域用来定义字符的宽度:tmAveCharWidth表示字体字符的平均宽度,tmMaxCharWidth表示字体最宽的字符的宽度。Windows中使用两种类型的字体,一类是固定宽度的字体,固定宽度的字体的每个字符的宽度是一样的,这样tmAveCharWidth和tmMaxCharWidth两值相等;另一类是可变宽度的字体,对于这类字体,每个字符占用的宽度不一样。例如, 字符“w”和“i”的宽度就不同,使用可变宽度的字体可以绘制紧凑的文本。
可以使用函数GetTextExtent计算出一个特定的文本行的宽度和高度,使用函数GetTextMetrics可以得到字符的有关尺寸。
接着是WM_PAINT的代码:
1 case WM_PAINT: 2 // hdc = BeginPaint(hWnd, &ps); 3 // RECT rt; 4 // GetClientRect(hWnd, &rect); 5 // DrawText(hdc, "xxxx", -1, &rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); 6 // EndPaint(hWnd, &ps); 7 // break; 8 9 hdc = BeginPaint(hWnd, &ps); 10 line =0; 11 if((fp=fopen("e:\\xxx.txt","r"))!= NULL) //此处文件地址要自己修改 12 { 13 while(!feof(fp)) { 14 int i = 0; 15 char ch; 16 while((ch = fgetc(fp)) != '\n' && ch != EOF) //换行则调用TextOut显示 17 szBuffer[i++] = (char)ch; 18 TextOut(hdc, xChar, line*yChar, szBuffer, i); //xChar是每行前面留出xChar宽度的空白,line*yChar是计算该行的纵坐标 19 line++; //很有趣的是,可以尝试把xChar换成0,把line*yChar换成0看看效果,会发生覆盖 20 } 21 fclose(fp); 22 } 23 EndPaint(hWnd, &ps); 24 break;
三、工程说明
首先新建一个Hello World的win32 application,然后在主要的cpp中做如下修改:
1. 加入两个头文件:
#include <windows.h>
#include <stdio.h>
2. 修改WndProc函数:
WndProc函数中需要加入WM_CREATE消息处理并修改自动生成的WM_PAINT消息处理。
附:WndProc函数代码,记得要加上两个头文件。
1 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 2 { 3 int wmId, wmEvent; 4 PAINTSTRUCT ps; 5 HDC hdc; 6 TCHAR szHello[MAX_LOADSTRING]; 7 LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); 8 9 //声明一些要用到的变量 10 int line; 11 TEXTMETRIC tm; 12 static int xChar, yChar; 13 char szBuffer[256]; 14 FILE *fp; 15 16 switch (message) 17 { 18 case WM_COMMAND: 19 wmId = LOWORD(wParam); 20 wmEvent = HIWORD(wParam); 21 // Parse the menu selections: 22 switch (wmId) 23 { 24 case IDM_ABOUT: 25 DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); 26 break; 27 case IDM_EXIT: 28 DestroyWindow(hWnd); 29 break; 30 default: 31 return DefWindowProc(hWnd, message, wParam, lParam); 32 } 33 break; 34 35 //加入创建窗口的消息处理 36 case WM_CREATE: 37 hdc = GetDC(hWnd);//从OS借用设备 38 GetTextMetrics(hdc, &tm);//获取显示设备上下文 39 xChar = tm.tmAveCharWidth;//设备的字符平均宽度 40 yChar = tm.tmHeight + tm.tmExternalLeading;//设备的字符高度 41 ReleaseDC(hWnd, hdc);//释放设备 42 break; 43 44 //修改自动生成的绘图消息处理 45 case WM_PAINT: 46 // hdc = BeginPaint(hWnd, &ps); 47 // RECT rt; 48 // GetClientRect(hWnd, &rect); 49 // DrawText(hdc, "xxxx", -1, &rect, DT_CENTER|DT_SINGLELINE|DT_VCENTER); 50 // EndPaint(hWnd, &ps); 51 // break; 52 53 hdc = BeginPaint(hWnd, &ps); 54 line =0; 55 if((fp=fopen("e:\\xxx.txt","r"))!= NULL) //此处文件地址要自己修改 56 { 57 while(!feof(fp)) { 58 int i = 0; 59 char ch; 60 while((ch = fgetc(fp)) != '\n' && ch != EOF) //如果该行结束则立即调用TextOut显示该行 61 szBuffer[i++] = (char)ch; 62 TextOut(hdc, xChar, line*yChar, szBuffer, i); //xChar是每行前面留出xChar宽度的空白,line*yChar是计算该行的纵坐标 63 line++; //很有趣的是,可以尝试把xChar换成0,把line*yChar换成0看看效果 64 } 65 fclose(fp); 66 } 67 EndPaint(hWnd, &ps); 68 break; 69 case WM_DESTROY: 70 PostQuitMessage(0); 71 break; 72 default: 73 return DefWindowProc(hWnd, message, wParam, lParam); 74 } 75 return 0; 76 }
PS:不知道,上面链接的网站的内容是哪本书上的,如果有读者知道,希望留言告知一下哈,谢啦。本人邮箱:huanqing2010@gmail.com