随笔-341  评论-2670  文章-0  trackbacks-0

    之前一边做脚本引擎,一边山寨一个自绘的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。


posted on 2011-10-11 07:42 陈梓瀚(vczh) 阅读(5027) 评论(11)  编辑 收藏 引用 所属分类: 2D

评论:
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-11 17:08 | phoenixbing
终于更新博客了,没有重磅炸弹来点小品文也行  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-11 18:25 | DiryBoy
一直觉得WPF Layout的Measure和Arrange两个方法好坑爹  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-11 19:31 | 陈梓瀚(vczh)
@phoenixbing
重磅炸弹岂能天天有,现在不像读书那会儿了,这个博客在08和09年的时候几乎每一两天就更新……  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-11 19:32 | 陈梓瀚(vczh)
@DiryBoy
其实,我也是这么做的,因为实在想不出更好的——唯一的改变就是我没有把arrange的结果存下来,每次都重新算不过反正很快,啊哈哈哈  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-11 19:36 | megax
DirectWrite  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2011-10-12 11:55 | sblz
XP选手表示D2D毫无鸭梨,用不到。。。  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2012-01-11 18:32 | lidongwei
你好,我有一部份代码要从GDI 上转到 Direct2d上,但用到了SetROP2函数,
查了很长时间,Direct2d好像没有直接支持光栅操作的函数,所以请教下:Direct2d里怎么能实现类似于SetROP2的操作。谢谢了。  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2012-01-11 19:51 | 陈梓瀚(vczh)
@lidongwei
因为在显卡里默认都是浮点运算(哪怕是RGBA也会每一个通道都转换成0-1的float)所以我觉得没戏了……除非把那一部分在D3D做,然后你自己写shader做ROP。  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2012-01-12 01:16 | lidongwei
@陈梓瀚(vczh)
谢谢。我去研究研究 像素着色器的东西。  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2013-02-14 18:10 | defined(LIUNX)
LZNB..不错此标题让我们这些菜鸟何堪,不过话说测量字体貌似不止一种方法,只要对点阵字库进行解码且检测每个文字的边缘几个测出字体的大小,因为字体就想birmap一样也是按位点真存储的,因此根据存储在字库中的每一位(用动态数组(vector array[向量数组])将每一位按位存储FB之后判断FB中得register的MAX_WIDTH/MAX_HEIGHT应该也行)..表设计哦本人菜鸟还没学到FreeType..D3D也还没开始接触,还多指教(就是觉得标题有点刺眼)  回复  更多评论
  
# re: 偶尔发布一下弱智知识——如何用Direct2D测量文字大小 2013-03-08 16:45 | 陈梓瀚(vczh)
@defined(LIUNX)
我很想跟你说,文字其实是一堆bezier曲线,只有当size很小的时候才是保存点阵的。  回复  更多评论
  

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理