在给定像素偏移量的字符串中计算字符索引的最佳方法

本文关键字:计算 字符 索引 方法 最佳 字符串 像素 偏移量 | 更新日期: 2023-09-27 18:07:57

相关问题:基于像素偏移获取字符串索引

我知道这很接近那个问题,但这不是问如何直接做到这一点,而是问如何最好地做到这一点。


我正在实现我自己的Windows窗体的文本框(因为RichTextBox吸),我试图找到最好的方法,给定的字符串已经绘制在屏幕上,计算鼠标的字符。问题是字符可以是可变宽度的。

我想到了两种可能性:

  1. 执行Graphics.MeasureCharacterRange 每次鼠标移动时,以二进制搜索方式在鼠标经过的行上(如顶部链接的问题所建议的)

  2. 保存每行每个字符的偏移量列表

(1)会有不好的表现,并且

(2)将是内存效率低下的,并且使键入一个字符成为一个O(n)操作(因为您必须调整它之后的每个字符的偏移量)不可能精确地完成,因为Graphics.MeasureCharacterRange不精确(它为一个字符返回一个值,为另一个字符返回另一个值,并且在一个字符串中为它们两个返回一个完全不同的值[不等于前面两个值加在一起]。例如,W将是16像素宽,f将是5像素宽,但Wf是20像素宽。这些数字来自实际测试。

所以我正在寻找一个更好的策略来做到这一点,最好是一个需要最小的空间和0(1)计算复杂度的策略(尽管我很乐意牺牲一点内存效率来换取速度效率)。

在给定像素偏移量的字符串中计算字符索引的最佳方法

我认为你不必做0(1)。0(1)假设每个额外的字符对所有之前的字符都有影响,但实际上不会。我最多能看到每个单词的0(1),这应该是非常快的。听起来你需要的是一种存储方式;1每个单词的位置,2每个唯一的单词,3单词中每个字母的宽度。这将显著减少存储并提高查找速度。比如:

IEnumerable<TextLocation> TextLocations = ...;
internal class TextLocation
{
    public RectF BoundingBox { get; set; }  //this is relative to the textbox
    public TextWord TextWord { get; set; }
}
internal class TextWord
{
    public string Text { get; set; }
    public IEnumerable<LetterInfo> Letters { get; set; }
}
internal class LetterInfo
{
    public char Letter { get; set; }
    public float left { get; set; }  //these would be relative to the bounding box
    public float right { get; set; } //not to the textbox
}

那么你也许可以这样做

var tl = TextLocations.FirstOrDefault(x => x.BoundingBox.Left < Mouse.X 
                                           && x.BoundingBox.Right > Mouse.X
                                           && x.BoundingBox.Top < Mouse.Y
                                           && x.BoundingBox.Bottom > Mouse.Y)
if (tl != null)
{
    //tl.TextWord.Text is the Word ("The", "Lazy", "Dog"...)
    var letter = tl.TextWord.Letters
                   .FirstOrDefault(x => Mouse.x - tl.BoundingBox.left > x.left
                                        Mouse.x - tl.BoundingBox.left < x.right);
    if (letter != null)
    {
        // you get the idea
    }                              
}