当前位置:C++技术网 > 资讯 > DrawText自动识别换行符和实现多行输出即自动换行

DrawText自动识别换行符和实现多行输出即自动换行

更新时间:2016-01-10 15:47:13浏览次数:1+次

    在文章《TextOut如何显示多行文本,TextOut函数使用全面分析》中,我们知道了,TextOut不能直接支持自动换行和多行显示。多行显示意思是遇到\r\n这样的符号能够自动多行显示,而自动换行就是遇到客户区边界的时候能够自动换行显示。如果有了两个换行的支持,那文字显示将会轻松不少。然而在TextOut中却要大费周折才能实现。
    以上的问题,在DrawText函数得到了完美的解决。
    DrawText函数的声明如下:
int DrawText(HDC hDC,LPCTSTR lpString,int nCount,LPRECT lpRect,UINT uFormat);
    DrawText函数输出的位置是以矩形区域的形式指定的。如果只是简单输出一行文字,那么就显得繁杂了。因为你要先构造一个矩形,然后再传给函数。相比之下,TextOut函数则简单的通过xy坐标指定输入位置即可。也正是因为这个矩形,才给格式化字符串以及各种特性带来了支持。试想一下,如果没有一个指定的范围,如何执行对齐?如果没有参考的边界范围,是无法做到的。在一个坐标系中,平面范围是无限的哦。你要明白这个矩形区域的作用就好。有了设置的矩形区域的限制,当字符串超出矩形范围时,GDI系统会自动将字符串调整到下一行输出。

    DrawText也支持识别\r、\n和\r\n三个换行标识符。如果遇到他们三个的任何一个组合,都会执行换行显示余下的字符串。而且,这个换行是默认的格式。也就是说,你不用设置任何格式,DrawText也会遇到\r、\n或\r\n时自动换行显示。效果如下图所示:

默认显示的格式会自动识别换行符和自动换行显示字符串

【默认显示的格式会自动识别换行符和自动换行显示字符串】
    设置字符串的格式的参数就是最有一个参数。如果你不想设置格式,也就是使用默认的格式,传入NULL即可。NULL即0,同时,DT_TOP和DT_LEFT格式说明的宏定义也是0。如果传入NULL,即默认使用DT_TOP和DT_LEFT的格式输入字符,也就是以顶对齐和左对齐输出文字。
    对于对齐方式的理解,可以参考文章《SetTextAlign设置文本对齐方式1:水平对齐的右对齐理解误区分析》和《SetTextAlign设置文本对齐方式2:垂直方向对齐方式的深入理解分析》。

    虽然DrawText默认支持遇到\r、\n或\r\n时会自动换行。如果你不想换行,也就是强制单行显示,那么你可以将格式添加DT_SINGLELINE,这样就不在将\r、\n或\r\n作为换行的标志,而当做一个不认识的字符,即显示为黑心方块,同时也不会换行显示字符串了。如下图所示:

单行显示字符串格式下的换行符显示为黑心块

【单行显示字符串格式下的换行符显示为黑心块】
    如果你想支持字符串遇到边界时就自动换行的话,需要设置格式DT_WORDBREAK。这个格式的意义在于,一个单词或者汉字需要完整的显示出来。如果一个单词或者汉字只有一部分能显示出来,另外一部分被遮盖了,就要换行显示。默认的一个特性就是,字符只要超过边界,都会自动换行,而且是以整个单词为单位的换行。比如word就是一个单词,要换行就是word整个显示在下一行,要么就是都在上一行,不会出现wo在上一行,rd在下一行的样子。如果要让字符串到达客户区的边界自动换行,你只需要将DrawText参数中的矩形设置为客户区的矩形即可。
    有了默认的自动识别换行符合DT_WORDBREAK格式说明,DrawText就很好的支持了换行符和边界自动换行两个特性了。要想设置多个格式,可以使用位或|将其组合起来。

    需要说明的是,前面说明的边界,是指的设置的矩形的边界,并不是指的客户区的边界。如果你的矩形设置的很小,那么只要到达矩形的边界就换行了。效果如下图所示:

即使没有到达客户区的边界,也换行了

【即使没有到达客户区的边界,也换行了】
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
TCHAR txt[100]=_T("C++技术网www.cjjjs.com 这仅仅是一个测试显示的文本。");
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TEXTMETRIC tm;
    RECT rect;
    switch (message)
    {
        case WM_PAINT:
            {
                hdc = BeginPaint(hwnd,&ps);
                SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
                GetClientRect(hwnd,&rect);
                //DrawText(hdc,txt,-1,&rect,DT_SINGLELINE);//强制单行显示,不会识别换行符,不会自动换行
                rect.right-=50;//将矩形的右边与客户区右边界拉开距离
                DrawText(hdc,txt,-1,&rect,DT_WORDBREAK);
                EndPaint(hwnd,&ps);
                return 0;
            }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
        break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_HAND);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass))return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,350,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}