在FormattedText上执行命中测试的好方法是什么?

时间:2009-02-12 04:19:24

标签: c# wpf text hittest

我正在使用FormattedText渲染文本,但似乎有任何方法可以对渲染输出执行每个字符命中测试。它是只读的,所以我基本上只需要选择,不需要编辑。

我使用RichTextBox或类似的,但我需要根据嵌入文本本身的控制代码输出文本,因此它们并不总是嵌套,这使得构建正确的内联元素非常复杂。我也有点担心该解决方案的性能;我有很多行,经常添加新行。

我看过GlyphRun,似乎我可以从它或相关的类中进行测试,但是我会重新实现很多功能,似乎应该有一个更简单的方法...

有没有人知道实现这个的好方法?

4 个答案:

答案 0 :(得分:4)

您可以从FormattedText对象获取每个字符的几何图形,并使用每个字符的边界进行命中测试。

var geometry = (GeometryGroup)((GeometryGroup)text.BuildGeometry(new Point(0, 0))).Children[0];
foreach (var c in geometry.Children)
{
  if (c.Bounds.Contains(point))
    return index;
  index++;
}

在OnRender中,您可以渲染这些几何对象而不是格式化文本。

答案 1 :(得分:3)

最好的方法是设计一个用于存储文本的良好数据结构,并考虑命中测试。一个例子可以是将文本分成块(单词,行或段落,具体取决于您的需要)。然后每个这样的块应该有一个边界框,应该在任何格式化操作中重新计算。还要考虑设计中的插入位置。

一旦你拥有了这样的设施,就可以很容易地进行命中测试,只需使用边界框即可。它还有助于后续操作,例如突出显示文本的特定部分。

答案 2 :(得分:1)

完全同意Sesh - 最简单的方法就是不要重新实现一大堆FormattedText功能,而是将你想要测试的单个项目分成他们自己的控件/内联。

考虑使用TextBlock并添加每个单词作为它自己的内联(或),然后绑定到内联的IsMouseDirectlyOver属性,我们添加委托给MouseEnter& MouseLeave事件。

如果你想对实际的字形进行像素级命中测试(即鼠标恰好在这个'i'的点上),那么你需要使用GlyphRuns并对字形进行手动命中测试(读:努力工作)。

答案 3 :(得分:1)

我参加晚会很晚 - 如果派对没有结束,而你不需要实际的角色几何,我发现这样的东西很有用:

 for (int i = 0; i < FormattedText.Text.Length; i++)
 {
            characterHighlightGeometry = FormattedText.BuildHighlightGeometry(new Point(), i, 1);
            CharacterHighlightGeometries.Children.Add(characterHighlightGeometry);
 }

BuildGeometry()仅包含角色的实际路径几何。 BuildHighlightGeometry()生成所有字符的外边界 - 包括 空格,因此可以通过以下方式找到空格的索引:

 foreach (var c in CharacterHighlightGeometries.Children)
        {
            if (c.Bounds.Contains(centerpoint))
            {
                q = c;
                cpos = index;
                break;
            }
            index++;
        }

希望这有帮助。