《Windows32 SDK教程》06章 简单的字体变换


小雅以前刚学VC时感觉号称强大的VC一点儿也不方便,想要一行中有不同字体和颜色也不行。其实,所谓“不行”是自己还不会,会了之后就觉得VC实在很强大。

一、GetDC()函数与BeginPaint()函数的区别

在前面章节中说过,设备文本句柄的方法也可用GetDC()函数,网上和有的书上说BeginPaint()函数只能用于WM_PAINT,其它地方一般不用,而GetDC()函数不能用在WM_PAINT下,其它地方可以用。关于这一点,小雅将通过一个例子来说明,这个例子是在指定位置显示一行文字,用DrawText()可以实现,但这儿用TextOut()函数来实现更方便。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    TCHAR szHello[64]="Wecome you to Http://www.quanxue.cn/!";
    HDC hdc;

    switch (message)
    {
        case WM_PAINT:
            hdc = GetDC(hWnd);

            SetTextColor(hdc, 0x0000FF);
            SetBkColor(hdc, 0xCDFAFF);
            TextOut(hdc,30,20,szHello,(int)strlen(szHello));

            //下面三行程序如果没有,窗口不正常地闪动
            RECT rt;
            GetClientRect(hWnd, &rt);
            ValidateRect(hWnd, &rt);    //让窗口有效区变得有效

            ReleaseDC(hWnd, hdc);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

在BeginPaint()函数的帮助上清楚地写着,这个函数将自动更新有效区。原来窗口只要发生任何改变,操作系统都会发送一个WM_PAINT消息来通知窗口刷新,在WM_PAINT中使用BeginPaint()函数,这个函数自动告诉操作系统窗口已经是最新的了。而GetDC()没有这个功能,因此GetDC()一般不用于WM_PAINT消息中,如果一定要在WM_PAINT中使用,那就要用ValidateRect()函数来手动刷新窗口。

二、改变字体大小使文字整行显示

在一行中显示不下时,可以改变字体的大小来使一行能够显示。字体和后面章节中讲到的画笔、画刷的使用方法是一样的,都是调用SelectObject()函数来把字体句柄与设备文本句柄进行绑定,同时得到绑定前的字体句柄,用完之后,不能忘记把原来的字体句柄绑定回去,这样,后面如果还有程序的话,可以不受任何影响。

创建字体是用CreateFont()函数来实现的,这儿说的“创建字体”并不是自创一个欧体还是柳体,而是创建一个字体对象,其中包括文字的宽度、高度、角度等许多信息。创建的字体用完之后也一定要手动删除,删除字体用DeleteObject()函数。

下面的例子只改变宽度、高度和字体,当窗口改变大小时,用窗口的宽度除以字符串长度,得到单个字符的宽度,用窗口高度当作字符高度,当然上下左右都要空一点位置,这样比较美观。例子中rc.right-20和rc.bottom-20就是要上下左右都空10象素。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HFONT hFont, hFontOld;
    char *str="劝学网";
    int  width, height;

    switch (message)
    {
        case WM_PAINT:
            RECT rc;
            hdc = BeginPaint(hWnd, &ps);
            GetClientRect(hWnd, &rc);
            SetBkMode(hdc, TRANSPARENT);

            width = (rc.right - 20) / (int)strlen(str);
            height = rc.bottom - 20;
            hFont = CreateFont(
                        height,      //字体的逻辑高度
                        width,       //逻辑平均字符宽度
                        0,           //与水平线的角度
                        0,           //基线方位角度
                        FW_REGULAR,  //字形:常规
                        FALSE,       //字形:斜体
                        FALSE,       //字形:下划线
                        FALSE,       //字形:粗体
                        GB2312_CHARSET,          //字符集
                        OUT_DEFAULT_PRECIS,      //输出精度
                        CLIP_DEFAULT_PRECIS,     //剪截精度
                        PROOF_QUALITY,           //输出品质
                        FIXED_PITCH | FF_MODERN, //倾斜度
                        "隶书"                   //字体
                    ); 
            hFontOld = (HFONT)SelectObject(hdc, hFont);       //选择字体
            SetTextColor(hdc, 0xC0C0C0);
            TextOut(hdc, 10, 10, str, (int)strlen(str));
            SelectObject(hdc, hFontOld);                      //选择旧字体
            DeleteObject(hFont);                              //删除新字体

            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

三、设置文字的字体、大小、方向

在上面的例子中,创建字体时变换了文字的方向。

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HFONT hFont, hFontOld;
    char *str1="小 雅";
    char *str2="劝学网SDK教程";
    char *str3="www.quanxue.cn";
    int  width, height;

    switch (message)
    {
        case WM_PAINT:
            RECT rc;
            hdc = BeginPaint(hWnd, &ps);
            GetClientRect(hWnd, &rc);
            SetBkMode(hdc, TRANSPARENT);

            width = (rc.right - 20) / (int)strlen(str1);
            height = rc.bottom - 20;
            hFont = SetMyFont(hdc, (LPCTSTR)"黑体", width, height, 0);   //创建字体
            hFontOld = (HFONT)SelectObject(hdc, hFont);       //选择新字体
            SetTextColor(hdc, 0xC0C0C0);
            TextOut(hdc, 10, 10, str1, (int)strlen(str1));
            DeleteObject(hFont);                              //删除新字体

            hFont = SetMyFont(hdc, (LPCTSTR)"楷体", 0, 32, 450); //创建字体
            SelectObject(hdc, hFont);                         //选择新字体
            SetTextColor(hdc, RGB(0, 0, 255));
            TextOut(hdc, -3, rc.bottom-16, str2, (int)strlen(str2));
            DeleteObject(hFont);                              //删除新字体

            hFont = SetMyFont(hdc, (LPCTSTR)"宋体", 0, 32, -450);//创建字体
            SelectObject(hdc, hFont);                         //选择字体
            SetTextColor(hdc, RGB(255, 0, 0));
            TextOut(hdc, 16, 0, str3, (int)strlen(str3));
            SelectObject(hdc, hFontOld);                      //选择旧字体
            DeleteObject(hFont);                              //删除新字体

            EndPaint(hWnd, &ps);
            break;
        case WM_DESTROY:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

HFONT SetMyFont(HDC hdc, LPCTSTR face, int width, int height, int angle)
{
    HFONT hFont;
    hFont = CreateFont(
                height,      //字体的逻辑高度
                width,       //逻辑平均字符宽度
                angle,       //与水平线的角度
                0,           //基线方位角度
                FW_REGULAR,  //字形:常规
                FALSE,       //字形:斜体
                FALSE,       //字形:下划线
                FALSE,       //字形:粗体
                GB2312_CHARSET,          //字符集
                OUT_DEFAULT_PRECIS,      //输出精度
                CLIP_DEFAULT_PRECIS,     //剪截精度
                PROOF_QUALITY,           //输出品质
                FIXED_PITCH | FF_MODERN, //倾斜度
                face                     //字体
            ); 
    return hFont;
}