当前位置:C++技术网 > 精选软件 > SetTextAlign设置文本对齐方式:1 水平对齐的右对齐理解误区分析

SetTextAlign设置文本对齐方式:1 水平对齐的右对齐理解误区分析

更新时间:2015-12-07 16:51:39浏览次数:1+次

    我们在WM_PAINT消息处理时,最常用的就是输出文本。文本输出我们可以使用DrawText和TextOut两个函数之一,DrawText函数指定字符串长度时可以传入-1表示字符串是以空字符结尾的,这样就不用去计算字符串的长度,比较方便。当然你可以可以传入字符串的长度值。而TextOut函数则只能传入字符串的长度值指定长度,不能使用-1。而DrawText函数指定输出文字的起始坐标是通过矩形区域,所以不方便,TextOut直接在参数输入xy坐标很方便。
    两个函数都要求指定输出文字的起始坐标xy的值。这个坐标是相对于客户区的坐标,客户区默认情况下左上角为原点(0,0),从左到右为x轴正向,从上到下为y轴正向。
    默认情况下,也就是简单的输入起始坐标,然后传入字符串和字符串长度,就可以输出文字了。当然,两个函数都要hdc设备描述表句柄作为第一个参数。默认情况下,我们可以看到文字是从左到右输出的,第一个字紧靠着输入的x坐标,实际上就是从x坐标处开始输出的。这就是左对齐方式输出字符串,是默认的方式。在WM_PAINT消息处理中,我们写这样的代码就可以了,代码如下:
hdc = BeginPaint(hwnd,&ps);
TextOut(hdc,0,0,_T("默认左对齐:C++技术网http://www.cjjjs.com"),lstrlen(_T("默认左对齐:C++技术网http://www.cjjjs.com")));
    左对齐是水平方向对齐的一种,另外的就是右对齐。其实左对齐一般我们都比较好理解,和我们写字的顺序和方向一致。而右对齐有时候会给初学者带来疑问。可能你比较熟的情况下,也很容易理解右对齐。不过我们来讨论右对齐的问题,就会更加清晰的去分析,而不是大概的认为是那么回事就行了的。
    那么我们先来看看我画的一张图片,很好的说明了这个问题。看下图:
    SetTextAlign文字对齐方式
    我想你一开始也觉得这个东西没什么好讲的。大家凭着第一感觉,就知道怎么回事,我也是这么想的。不过我再仔细理性的想想,其实其中还是有一些比较容易让初学者迷惑的地方。我们凭感觉或者是使用各种排版软件得到的直观的感觉,左对齐就是靠近最左边,右对齐就是靠近最右边开始。然而这里是编程,所以,和你使用排版软件得到的理解大相径庭。这也是为什么很多人理解这个右对齐甚至是左对齐都感觉很疑惑的原因所在。也正是基于这样的考虑,我才特地分析一下,让你编程学习中来正确的理解这个水平对齐方式的问题。其实,这个原理就在图中一目了然。可能你还没有太明白,或者和排版软件给你的感觉还是没有区分开来,那么我就仔细的分析一下。
    那么左对齐我们在排版软件的理解就是,紧靠左边,文字从左向右输出。最多,文字可以缩进,实际上,缩进就是我们在程序里对文字的输出起始x值变大,这样其实位置就缩进了。这一点,我想你也很快就接受了。
    按照上图说明,左对齐的字符串输出的起始x就是交叉点的输出文字的起点。这个起点我们可以设置,就是TextOut的第二个参数指定的值。也就是,文字开始输出的位置是由程序员指定的,可以是水平方向的任何一个位置。而在排版软件最左边,或者是窗口的边框,一般就是默认x为0的位置(也可能是为了美观,x的数值比较小,不至于文字紧贴着左边框输出变得很丑),也就是与文字输出起始x坐标紧挨着,这样我们在不缩进的情况下,看到的左对齐就是紧紧挨着左边。而缩进后,输出文字的x值就向右增大了,这样,文字就和左边界隔远了,就是缩进的效果。
    然而在编程中,我们就不会像使用排版软件一样被左边给限制了。我们输出文字时并没有硬性的边界束缚,当然你要是从窗口最左边输出,就感觉和排版软件差不多。然而你可以随便指定x的值,这样就可以离左边框远远的,你可以将x值设置的比较大,就比较靠近窗口水平中心了,就是上图那样的了。
    那么你输出文字,就是从这个靠中心的水平位置开始输出了。从这个x处向右输出文字,就是左对齐。输出的字符串,最靠左的字就是字符串的第一个字,一直向右输出直到右边框,超过右边框的就看不到了。
    而右对齐,在这个图的帮助下,你就可以比较直观的理解了。右对齐是紧靠着x位置向左输出文字,只不过,最后一个字最靠近x位置,字符串第一个字离x最远。或者换种方式理解,右对齐就是字符串的字从最后一个开始输出,向左方不断的从字符串最后一个字到第一个字输出,直到输出所有的字符。超过左边框的文字就看不到了。
    这里的右对齐就和排版软件的右对齐表面上完全不一样了,甚至会让你凌乱。我这里来把两者的关系说一下,你就完全明白了。
    排版软件的对齐是面向电脑小白的,是基于文字排版所说的。而我们编程中的对齐是基于坐标系的实际的实现方式。两个是不一样的。排版软件的右对齐是将x值设置为最右边的值,然后设置文字的对齐方式为右对齐,这样输出的方向就是排版软件所看到的。在编程中并不是设置了右对齐就可以和排版软件那样的。这一点不仅理解好是非常重要的,当你在做排版软件时更是要将编程中对齐方式和排版中的对齐方式区别开来。
    我们写下面这几行代码输出三行文字:
TextOut(hdc,0,0,szStr1,lstrlen(szStr1));//-默认对齐方式
SetTextAlign(hdc,TA_RIGHT);//-设置右对齐
TextOut(hdc,100,20,szStr2,lstrlen(szStr2));//-右对齐的输出
SetTextAlign(hdc,TA_LEFT);//-设置左对齐
TextOut(hdc,0,40,szStr3,lstrlen(szStr3));//-左对齐输出
    设置右对齐后,我将x值设置为100,是让文字可以从x=100的位置开始向左输出,否则也让x=0的话,第二行就看不到文字了。效果图如下:
 

    从图中你可以看到,右对齐的虽然设置了x为100,还是没有完整显示完字符串,超出左边框的看不到了。如果你想实现word里的右对齐,就要将x设置为窗口客户区最右边的坐标了。这个留给你自己动手试试效果吧。

    下面是完整的测试代码:


#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    TCHAR szStr1[]=_T("默认左对齐:C++技术网http://www.cjjjs.com");
    TCHAR szStr2[]=_T("C++技术网http://www.cjjjs.com,设置右对齐");
    TCHAR szStr3[]=_T("设置左对齐:C++技术网http://www.cjjjs.com");
    switch (message)
    {
     case WM_PAINT:
         hdc = BeginPaint(hwnd,&ps);
         TextOut(hdc,0,0,szStr1,lstrlen(szStr1));
         SetTextAlign(hdc,TA_RIGHT);
         TextOut(hdc,100,20,szStr2,lstrlen(szStr2));
         SetTextAlign(hdc,TA_LEFT);
         TextOut(hdc,0,40,szStr3,lstrlen(szStr3));
         EndPaint(hwnd,&ps);
        return 0;
     case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
     default:
         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(GRAY_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    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,440,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

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