第17章 文本和字体_17.1-17.2 简单文本输出、 字体的背景知识

17.1 简单文本输出

17.1.1 文本输出函数

(1)TextOut(hdc,xStart,yStart,pString,iCount)

  ①xStart和yStart使用的是逻辑坐标,TextOut并不以NULL来做字符串的结束,需指定字符的个数iCount的值

  ②SetTextAlign会改变xStart和yStart的含义

SetTextAlign

坐标值的含义

TA_LEFT

xStart:第一个字符的左侧坐标

TA_RIGHT

xStart:最后一个字符的右侧坐标

TA_CENTER

xStart:字符串正中间点的坐标

TA_TOP

yStart:所有字符的最高点,即所有字符在yStart的位置之下

TA_BOTTOM

yStart:所有字符都在yStart位置之上

TA_BASELINE

yStart:表示字符串在基线位置,即小写字母q或y下伸部分在基线之下。

TA_UPDATECP

1、忽略xStart和yStart,而是由如MoveToEx或LineTo等一些会改变当前坐标的函数指定的当前值。CP==Current Position?

2、此时TextOut函数也会改变坐标当前值,对于TA_LEFT,新坐标值在字符串结尾位置;对于TA_RIGHT,当前坐标值在新字符串开始位置;对于TA_CENTER,则仍在中间位置,不会改变。

(2)TabbedTextOut(hdc,xStart,yStart,pString,iCount,iNumTabs,piTabStops,xTabOrigin);

  ①当遇到字符串包含制表符(‘ ’或0x09)时,会被转成空白位置和个数由xTabOrign和piTabStops数组里元素共同决定。

  ②iNumTabs指定piTabStops中元素的个数

  ③piTabStops :TabStop位置的数组(逻辑单位),。表示每个制表符开始的位置,元素必须按升序存储。注意,元素表示的是个相对位置,即相对于xTagOrigin的位置偏移,比如元素元素分别为{40,80,120,160,200}表示第1个tab从xTagOrgin+40像素的地方开始输出,第2个从xTagOrgin+80,第3个从xTagOrgin+120开始输出,依此类推…

  ④如果iNumTabs值为0,且piTabStops值为NULL则制表符将会按平均字符宽度的8倍来扩展。

  ⑤iCount为-1时,遇自动结束。

  ★先依次输出字符串中的每个字符。遇到第n个 时,从piTabStops数组依次比较,进而找到这个tab的开始位置(找到的元素索引为i。注意,i不一定等于n),就可以确定tab的位置为xTabOrigin+piTabStops[i]。如果在数组中找不到,就按默认的字符宽度的8倍,去计算出这个tab的位置。若这个tab位置前的字符不够时,则用空格补全。

【实例分析1】——xTabStop==0时(本例用系统等宽字符,每个字符的平均宽度为8像素)

  TCHAR szText[] = TEXT("abcdfg hi jklmnopqrstuvwxyz h");//3个

  TabbedTextOut(hdc,0, 0, szText, -1,0, NULL,0);//默认Tab位置是字符宽度的8倍。

  ①第1个Tab位为刻度8的位置(1*字符宽度的8倍),因刻度8之前只有6个字符,所以补充2个空格字符,然后输出hi两个字符,然后遇第2个Tab。

  ②第2个Tab为16(2*字符宽度的8倍)的位置(即刻度16)处开始,由于字符数不够,得再补充6个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

  ③第3个Tab开始的位置应为8的倍数,即8、16、24、32或40等,但因8、16、24、32处要么被字符占用,要么被以前的两个Tab占用,所以第3个Tab从40开始,然后输出h字符。

【实例分析2】——xTabStop==10*8时,即Tab位的原点在图中刻度10的位置。

  TCHAR szText[] = TEXT("abcdfg hi jklmnopqrstuvwxyz h");//3个

  TabbedTextOut(hdc,0, 0, szText, -1,0, NULL,10*8);//与上例唯一的不同,xTabStop

  ①第1个Tab位为10+8的位置(其中10为xTabStop,8与例一样),即上图中刻度的18开始,因刻度18之前只有6个字符,所以补充12个空格字符,然后输出hi两个字符,然后遇第2个Tab。

  ②第2个Tab为(10+16)的位置(其中10为xTabStop)处开始,由于字符数不够得再补充6个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

  ③第3个Tab开始的位置应为10+(8的倍数),即18、26、34、42或50等,但因8、18、26、34、42处要么被字符占用,要么被以前的两个Tab占用,所以第3个Tab从50开始,然后输出h字符。

【实例分析3】——讨论xTabStop==0时

  TCHAR szText[] = TEXT("abcdfg hi jklmnopqrstuvwxyz h");//3个

  int iTabStops[] = { 5 * 8, 6 * 8, 15 * 8, 30 * 8,45 * 8 };//每个字符宽度是8

                                                                                       //元素的含义表示Tab位在第5、6、15、30、45刻度处

  TabbedTextOut(hdc,0, 0, szText, -1,iLen, iTabStops,0);

  ①第1个Tab位为15的位置(iTabStops的第3个元素),即上图中刻度的15开始,

因为第1个元素5,但其位置己被字符f占用,第2个元素6,其位置己被g占用,所以第1个Tab从第3个元素,即刻度15的位置开始,因前面只有6个字符,得补9个空格。

  ②第2个Tab为刻度30的位置(即第4个元素)处开始,由于字符数不够得再补充13个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

  ③第3个Tab本应从刻度45开始,但被占用,而此时数组中的元素己经用尽,所以按默认的8的倍数,即刻度48的位置开始,所以补1个0,然后输出h。

【实例分析4】——讨论xTabStop==10*8时,即xTabStop从10的刻度开始

  TCHAR szText[] = TEXT("abcdfg hi jklmnopqrstuvwxyz h");//3个

  int iTabStops[] = { 5 * 8, 6 * 8, 15 * 8, 30 * 8, 45 * 8 };//每个字符宽度是8

                                                                                         //元素的含义表示Tab位为xTabStop加5、6、15、30、45这些偏移开始

  TabbedTextOut(hdc,0, 0, szText, -1,iLen, iTabStops,10*8);

  ①第1个Tab位为10+5的位置(其中10为xTabStop,5为iTabStops的第1个元素),即上图中刻度的15开始,因a到g只有6个字符,得补9个空格。然后输出hi

  ②第2个Tab为10+15的位置(即第3个元素),而不是10+6(因为16位置被h占用),由于字符数不够得再补充8个空格字符。然后输出jklmnopqrstuvwxyz,此时再遇第3个字符。

  ③第3个Tab本应从刻度10+45开始(因为10+30被占用),所以补13个0,然后输出h。

(3)ExtTextOut(hdc,xStart,yStart,iOptions,&rect,pString,iCount,pxDistance);

  ①rect参数:当iOption==ETO_CLIPPED时,rect为剪切框;当iOption==ETO_OPAQUE时,rect为文本的背景框。这两个选项可以同时使用,也可以一个都不用。

  ②pxDistance是指向一个整型数组,指定了字符串中相邻字符间的像素间距。如果为NULL,则为默认字符间距。→可自由定制紧凑或宽松的字符间距。(注意:数组元素的个数要大于等于字符间隔的个数,即数组元素个数≥字符个数-1)。

(4)DrawText(hdc,pString,iCount,&rect,iFormat);

  ①iCount为-1时,自动计算字符串长度。

  ②iFormat

iForamt参数

含义

0

将以回车 (或0x0D)及换行 (或0x0A)分隔成多行文本。

DT_LEFT、

DT_RIGHT、

DT_CENTER

DT_VCENTER等

文本对齐标志

DT_SINGLELINE

单行文本,此时回车换行符无效。

DT_WORDBREAK

在临近边框的两个单词中换行

DT_EXTERNALLEADING

多行文本时,字符高度不含字体的外部间距,如果希望行间距包括这个外部间距,就要使用该标志。

DT_EXPANDTABS

默认两个制表位之间为八个字符宽度


 17.1.2  文本的设备环境属性 

(1)SetTextColor(hdc,rgbColor)或GetTextColor(hdc);//设置或获取文字颜色

(2)SetBkMode(hdc,iMode);设置背景模式:OPAQUE时表示不透明;TRANSPARENT(透明)

   ★当为TRANSPARENT时,会用背景色给虚线或点划线中间的空白部分着色。

(3)SetBkColor(hdc,rgbColor)//设置背景颜色

  ★调用当前系统颜色设定文本颜色或背景

      SetTextColor(hdc,GetSysColor(COLOR_WINDOWTEXT));

      SetBkColor(hdc,GetSysColor(COLOR_WINDOW));

   ★响应WM_SYSCOLORCHANGE消息:——随系统颜色的更改自动更改文本和背景色。

      Case WM_SYSCOLORCHANGE:InvalidateRect(hwnd,NULL,TRUE);break;

(4)SetTextCharacterExtra(hdc,iExtra);——字符间距,默认为0,否则为iExtra 

      ①iExtra为负数时,会被自动取绝对值,所以不能利用该函数让字符紧缩一点。

      ②iExtra是个逻辑单位。可以通过GetTextCharacterExtra取得当前字符间距。

17.1.3 使用库存字体

(1)获取特定库存字体:hFont= GetStockObject(iFont);//iFont为系统预定义标识符

(2)选入设置环境SelectObject(hdc,hFont);

(3)利用GetTextMetrics函数获取当前字体信息。

【TabbedTextOut程序】

#include "stdafx.h"
#include "TabbedTextOut.h"

#define MAX_LOADSTRING 100
// 全局变量: 
HINSTANCE hInst;                                // 当前实例
TCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名
// 此代码模块中包含的函数的前向声明: 
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                       _In_opt_ HINSTANCE hPrevInstance,
                       _In_ LPTSTR    lpCmdLine,
                       _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    // TODO:  在此放置代码。
    MSG msg;
    HACCEL hAccelTable;
    // 初始化全局字符串
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_TABBEDTEXTOUT, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);
    // 执行应用程序初始化: 
    if (!InitInstance(hInstance, nCmdShow))
    {
        return FALSE;
    }
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_TABBEDTEXTOUT));
    // 主消息循环: 
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return (int)msg.wParam;
}
//
//  函数:  MyRegisterClass()
//
//  目的:  注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
    wcex.cbSize = sizeof(WNDCLASSEX);
    wcex.style = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc = WndProc;
    wcex.cbClsExtra = 0;
    wcex.cbWndExtra = 0;
    wcex.hInstance = hInstance;
    wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDC_TABBEDTEXTOUT));
    wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName = NULL;//MAKEINTRESOURCE(IDC_TEST);
    wcex.lpszClassName = szWindowClass;
    wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    return RegisterClassEx(&wcex);
}
//
//   函数:  InitInstance(HINSTANCE, int)
//
//   目的:  保存实例句柄并创建主窗口
//
//   注释: 
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;
    hInst = hInstance; // 将实例句柄存储在全局变量中
    hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
    if (!hWnd)
    {
        return FALSE;
    }
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);
    return TRUE;
}
//
//  函数:  WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
int iTabStops[] = { 5 * 8, 6 * 8, 15 * 8, 30 * 8, 45 * 8 };
int iLen = sizeof(iTabStops) / sizeof(iTabStops[0]);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rc;
    TEXTMETRIC tm;
    int yPos = 50;
    TCHAR szBuf[50];
    int k = 0;
    static int cxClient, cyClient;
    static TCHAR szText[] = TEXT("abcdfg	hi	jklmnopqrstuvwxyz	h");
    switch (message)
    {
    case WM_CREATE:
        break;
    case WM_COMMAND:
        wmId = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // 分析菜单选择: 
        switch (wmId)
        {

        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));
        GetTextMetrics(hdc, &tm);
        GetClientRect(hWnd, &rc);
        //画刻度尺
        MoveToEx(hdc, 0, yPos, NULL);
        LineTo(hdc, rc.right, yPos);
        SetTextAlign(hdc, TA_CENTER);
        for (k = 0; k < 300; k++)
        {
            MoveToEx(hdc, k*tm.tmAveCharWidth, yPos, NULL);
            LineTo(hdc, k*tm.tmAveCharWidth, yPos + 10);
            if (k % 5 == 0)
            {
                TextOut(hdc, k*tm.tmAveCharWidth, yPos + 20, szBuf, wsprintf(szBuf, TEXT("%d"), k));
            }
        }
        for (k = 0; k < 300; k++)
        {
            MoveToEx(hdc, 10 * k*tm.tmAveCharWidth, yPos, NULL);
            LineTo(hdc, 10 * k*tm.tmAveCharWidth, yPos + 20);
            if ((k % 5) == 0)
            {
                MoveToEx(hdc, k*tm.tmAveCharWidth, yPos, NULL);
                LineTo(hdc, k*tm.tmAveCharWidth, yPos + 16);
            }
            SetBkMode(hdc, TRANSPARENT);
            SetTextAlign(hdc, TA_LEFT);
            //TextOut(hdc, cxClient / 2, cyClient / 2, szText, lstrlen(szText));
            //TabbedTextOut(hdc, 0, yPos - tm.tmHeight, szText, -1, 0, 0, 0);
            TabbedTextOut(hdc, 0, yPos - tm.tmHeight, szText, -1, iLen, iTabStops, 10 * 8);
            EndPaint(hWnd, &ps);
            break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    return 0;
}
第17章 文本和字体_17.2 字体的背景知识
 17.2 字体的背景知识

17.2.1 GDI字体分类

(1)点阵字体RasterFont(也称为位图字体)——不可缩放,但显示速度极快

字样名称

用途

System

用于SYSTEM_FONT字体

FixedSys

用于SYSTEM_FIXED_FONT字体

Terminal

用于OEM_FIXED_FONT字体

Courier

等宽的

MS Serif

MS Sans Serif

用于DEFAULT_GUI_FONT

Small Fonts

(2)笔画字体(StrokeFont)——有时也称为绘图仪字体

   ①由一系列的点和连接点的线段组成,可缩放

②当字号很小时,文本不清晰,很大时,笔画是单线条的,显得单薄。

③笔画字体的字样名称有:Modern、Roman、Script

17.2.2 TrueType字体

字样名称

字样名称

Courier New

Times New Roman Bold Italic

Courier New Bold

Arial

Courier New Italic

Arial Bold

Courier New Bold Italic

Arial Italic

Times New Roman

Arial Bold Italic

Times New Roman Bold

Symbol

Times New Roman Italic

17.2.3 属性和样式的区别

(1)TrueType字体中,粗体、斜体的Courier、Times New Roman和Arial都有单独的名称,是独立的字体。

(2)但是一般认为粗体或斜体只是同一种字体的不同属性,而不是不同的字体。Windows并没有完全解决这一问题。也就是设置斜体或粗体时即可以用属性,也可以用字样名称。从而也导致了在枚举系统可用字体列表时,必须要进行双重处理,增加了难度。

17.2.4 行间距和字间距

(1)点值(磅):1磅 =1/72英寸。

10磅字号:指“bq”的完整高度(不含字母上的重音符号),即=tmHeight –tmInternalLeading;

(2)行间距示意图

17.2.5 逻辑英寸问题

(1)逻辑英寸:定义显示器上96个或120个像素占据的距离为一个“逻辑英寸”

(2)使用特定点(磅)值显示文本的方法——“逻辑缇”(每个逻辑单位为1/1440英寸)

    SetMapMode(hdc,MM_ANSIOTROPIC);

    SetWindowExtEx(hdc,1440,1440,NULL); //表示1440个单位到对应1逻辑英寸,即

                                                              //1个逻辑单位为1/1440英寸。

    SetViewportExt(hdc,GetDeviceCaps(hdc,LOGPIXELSX),  //1逻辑英寸

                        GetDeviceCaps(hdc,LOGPIXELSX),NULL)://1逻辑英寸 

如12磅的字体 =12*1/72(英寸)=1440*12/72(逻辑单位)=240逻辑单位。即点值的20倍

原文地址:https://www.cnblogs.com/5iedu/p/4701154.html