偶尔发布一下弱智知识——如何用Direct2D测量文字大小

偶尔发布一下弱智知识——如何用Direct2D测量文字大小

    之前一边做脚本引擎,一边山寨一个自绘的native C++的GUI框架并且可以切换GDI或者Direct2D渲染模式。因为抄了WPF的那种高级自动布局功能,所以必然需要知道如何测量文字大小。Direct2D测量文字大小比较麻烦,不像GDI有直接函数,并且用中英文搜好像都没人直接给出结果,还有人在博客上写“这种事情好像办不到”这样的文字。不过经过我遍历MSDN,还是找到了一个曲线救国的方法的,直接上代码:

    首先是创建IDWriteTextFormat:

 1                      IDWriteFactory *  dwriteFactory = GetDirectWriteFactory();
 2                      IDWriteTextFormat *  format = 0 ;
 3                      HRESULT hr = dwriteFactory -> CreateTextFormat(
 4                          fontProperties.fontFamily.Buffer(),
 5                          NULL,
 6                          (fontProperties.bold ? DWRITE_FONT_WEIGHT_BOLD:DWRITE_FONT_WEIGHT_NORMAL),
 7                          (fontProperties.italic ? DWRITE_FONT_STYLE_ITALIC:DWRITE_FONT_STYLE_NORMAL),
 8                          DWRITE_FONT_STRETCH_NORMAL,
 9                          (FLOAT)fontProperties.size,
10                          L "" ,
11                           & format);
12                       if ( ! FAILED(hr))
13                      {
14                          format -> SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
15                           return  format;
16                      }
17                       else
18                      {
19                           return   0 ;
20                      }

    fontProperties是我自定义的一个结构就不用去管它了,参考MSDN就知道CreateTextFormat如何使用了。其中fontProperties.fontFamily是字体的名字。然后IDWriteTextFormat就扮演着GDI的“字体对象”的角色,可以用ID2D1RenderTarget进行绘制。ID2D1RenderTarget除了用IDWriteTextFormat当字体以外,还可以用IDWriteTextLayout当“添加多余信息的更复杂的字体”。测量文字的关键正是在这里。

    接下来我们借助IDWriteTextFormat来创建IDWriteTextLayout:

 1                      IDWriteTextLayout *  textLayout = 0 ;
 2                      HRESULT hr = GetDirectWriteFactory() -> CreateTextLayout(
 3                          oldText.Buffer(),
 4                          oldText.Length(),
 5                          textFormat,
 6                           0 ,
 7                           0 ,
 8                           & textLayout);
 9                       if ( ! FAILED(hr))
10                      {
11                          DWRITE_TEXT_METRICS metrics;
12                          hr = textLayout -> GetMetrics( & metrics);
13                           if ( ! FAILED(hr))
14                          {
15                              minSize = Size(( int )ceil(metrics.widthIncludingTrailingWhitespace), ( int )ceil(metrics.height));
16                          }
17                          textLayout -> Release();
18                           return ;
19                      }

    这里看minSize就知道如何测量文字的字体了。

    在这里放一张暂时的图片。我抄了WPF的那种方法,从布局和绘图元素直接开始可以构造GUI,因此演示了如何使用这些东西来创造一个Win7的按钮(带动画的哦)打开Vczh Library++3.0,下载代码并打开Candidate\GUI\GuiDemo\GuiDemo.sln,按F5就可以看到了效果了:



    这一个是Direct2D渲染的结果(我在工程文件指定了DXSDK的绝对路径,如果你们安装的地方不同改掉它既可编译了)。按钮基本上跟win7的效果一摸一样,但是这里使用Direct2D进行渲染。当按钮尺寸变化的时候,那个复杂的边框和里面的两个渐变和文字都可以自动对齐——但是这并不是hard code的,而是GUI的“布局功能”可以配置成这个样子。像这两个按钮一直处于右下角也是“布局功能”可以提供的功能。大家可以理解为这东西类似于C#的TableLayoutPanel。

    现在刚刚做好了按钮——跟WPF一样可以更换template,不过因为反正没人需要动态更换template所以我把template写在了构造函数里面,因此换肤这种事情就变得相当简单了——只要用布局功能跟图元拼凑成一个复杂的图形,然后实现各个控件所规定的“template接口”响应外观控制的消息就行了,内置动画支持(这个要运行的时候才能观察到)。

    为了方便,我在工程里面除了Debug和Release以外还加入了DebugDirect2D和ReleaseDirect2D两个配置,可以自由切换观看demo。


你可能感兴趣的:(偶尔发布一下弱智知识——如何用Direct2D测量文字大小)