园子里面的各位对于文本编辑器都貌似很感兴趣。近来wojilu的宣传工作告一个段落了(大神准备在出1.7正式版后,开始代码托管工作,同时希望在Release一个完美版之后,给更多的朋友使用,所以推广工作暂时停一下,自己的网站在做在线单词编辑器,还没有成形)所以抽空来讲讲文本编辑器的那些事情,以前发过此文,稍微修改一下下。VBNET写的各位C#的大人们,忍耐一下吧。

    文本编辑器,就是捕获键盘事件,获得输入字符,在控件表面绘制字符串,设定光标位置。这一系列的文章,将告诉大家所有这些操作该如何处理,有什么注意点。 这篇随笔将首先要讨论一个看似很简单,其实有很多注意点的小问题,如何获得字符串的长度(这个问题在处理光标位置,绘制被选中区域的时候,将起到决定性的 作用)。

    要知道字符串的长度,可能大家一下子想到的是Graphics的MeasureString,只要指定了字体和字符串后,用这个方法就能获得一个矩形的区 域,这个区域是Graphics对象用DrawString方法在空间表面绘制字符串时所要的区域。这个区域的宽度不就是我们想知道的字符串的宽度吗?

    开始的时候,我也是这么想的,但是使用后立刻发现MeasureString有很多问题。当然,其中有些问题我是对这个方法理解不足造成的,有的问题确实是MeasureString无能为力的。(如果哪位大侠知道解决方法,吼一下啊)

    1.尾部空格的问题。

    如果你使用MeasureString去测量两个字符串,一个在尾部有空格,一个在尾部没有空格,你将会发现,这两个字符串测量出来的宽度是一样的。例如 “TextEditor” 和 “TextEditor    ”的宽度是一样的。(全角和半角空格的命运一样,都被忽略不计了)。这个问题,其实是我对MeasureString方法理解不足造成的,其实 MeasureString的最后一个StringFormat标志位是可以设定是不是要忽略尾部空格的。

StringFormat标志位 说明
MeasureTrailingSpaces 包括每一行结尾处的尾随空格。在默认情况下,MeasureString 方法返回的边框都将排除每一行结尾处的空格。设置此标记以便在测定时将空格包括进去。

    当我解决这个问题的时候,当时有点小小的高兴,以为求字符串的宽度的问题就到这里为止了。其实真正的噩梦才刚刚开始。

    2.为什么用MeasureString测量出来的字符宽度,都不实际宽度稍微大一点啊?

    使用MeasureString测量出来的字符宽度,总是比实际宽度大一些,而且随着字符的长度增大,貌似实际宽度和测量宽度的差距也越来越大了。查了一下MSDN,找到了下面这个理由:

MeasureString 方法旨在与个别字符串一起使用,它在字符串前后包括少量额外的空格供突出的标志符号使用。

可能当时MS这样设计的出发点是好的,但是却不是我想要的方法。(光标的位置必须精确的在字符的后面)在Google上找了半天,终于找到了一个代替MeasureString的方法:

TextRenderer.MeasureText(注意:此方法在 .NET Framework 2.0 版中是新增的。)

Dim dc As IDeviceContext Dim text As String Dim font As Font Dim proposedSize As Size Dim flags As TextFormatFlags Dim returnValue As Size  returnValue = TextRenderer.MeasureText(dc, text, font, proposedSize, flags) 
参数
dc

测量文本所使用的设备上下文。

text

要测量的文本。

font

要应用于已测量文本的 Font

proposedSize

初始边框的 Size

flags

要应用于已测量文本的格式说明。

返回值
使用指定的 font 和格式绘制的 text 的 Size(以像素为单位)。

这个方法,要达到我需要的效果,需要注意设定2个地方:

proposedSize:需要把这个边框完全去掉,也就是说把这个Size的高度和宽度都设成0
flags:NoPadding 不在边框中添加空白边距

完成后的方法大概是这个样子的,输入参数是字符串,返回一个矩形区域。矩形区域的宽度就是字符串的精确宽度了。
Private Function MeasureText(ByVal strText As String) As Size
    'MeasureText:将边框设定为0,TextFormatFlags:NoPadding 不在边框中添加空白边距
    Return TextRenderer.MeasureText(Me.CreateGraphics, strText, mCodeFont, _
    New Size(0,0),TextFormatFlags.NoPadding)
End Function

    以前一直以为要测量字符串的长度,只要用MeasureString就可以了,现在看来,MeasureString还是有部分局限性的,也可能是我孤陋 寡闻,不知道如何正确使用MeasureString方法。MeasureString不去真正使用,光看文档,是不可能真正领会,真正了解这个方法的。 纸上得来终觉浅,绝知此事需恭行,大概就是这个意思吧。

作者: magicDict 发表于 2011-06-30 17:26 原文链接

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架
新浪微博粉丝精灵,刷粉丝、刷评论、刷转发、企业商家微博营销必备工具"