C# 在给定像素偏移量的情况下,计算字符串中字符索引的最佳方法

C# 在给定像素偏移量的情况下,计算字符串中字符索引的最佳方法,c#,winforms,string,textbox,measure,C#,Winforms,String,Textbox,Measure,相关问题: 我知道这很接近那个问题,但这不是问如何直接做,而是问如何最好地伪装 我正在为Windows窗体实现我自己的文本框(因为RichTextBox很烂),我正在尝试找到最好的方法,根据屏幕上绘制的字符串,计算鼠标停留的字符。问题是字符的宽度可以是可变的 我提出了两种可能性: 每次鼠标在鼠标所在行上以二进制搜索方式移动(如顶部链接的问题所示),都要进行Graphics.MeasureCharacterRange 保留每行每个字符的偏移量列表 (1) 会有糟糕的表现,并且 (2) 将导致内存

相关问题:

我知道这很接近那个问题,但这不是问如何直接做,而是问如何最好地伪装


我正在为Windows窗体实现我自己的文本框(因为RichTextBox很烂),我正在尝试找到最好的方法,根据屏幕上绘制的字符串,计算鼠标停留的字符。问题是字符的宽度可以是可变的

我提出了两种可能性:

  • 每次鼠标在鼠标所在行上以二进制搜索方式移动(如顶部链接的问题所示),都要进行
    Graphics.MeasureCharacterRange

  • 保留每行每个字符的偏移量列表

  • (1) 会有糟糕的表现,并且

    (2) 将导致内存效率低下,再加上使键入字符成为O(n)操作(因为必须调整每个字符后面的偏移量),再加上无法精确执行,因为
    图形。MeasureCharacterRange
    不精确(它为一个字符返回一个值,为另一个字符返回另一个值,并返回一个完全不同的值[不等于前两个加在一起的值]对于这两种类型,将它们合并为一个字符串。例如,
    W
    宽16像素,
    f
    宽5像素,但
    Wf
    宽20像素。这些数字来自实际测试。)


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

    我认为你不必做O(1)。O(1)假设每增加一个字符都会对前面的所有字符产生影响,但事实并非如此。充其量我会看到一个O(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
    }
    
    IEnumerable TextLocations=。。。;
    内部类TextLocation
    {
    public RectF BoundingBox{get;set;}//这是相对于文本框的
    公共文本字文本字{get;set;}
    }
    内部类文本字
    {
    公共字符串文本{get;set;}
    公共IEnumerable字母{get;set;}
    }
    内部类LetterInfo
    {
    公共字符字母{get;set;}
    public float left{get;set;}//这些将是相对于边界框的
    public float right{get;set;}//不指向文本框
    }
    
    然后你可以做一些类似的事情

    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
        }                              
    }
    
    var tl=TextLocations.FirstOrDefault(x=>x.BoundingBox.Left鼠标.x
    &&x.BoundingBox.TopMouse.Y)
    如果(tl!=null)
    {
    //Text是单词(“the”,“Lazy”,“Dog…”)
    var字母=tl.TextWord.Letters
    .FirstOrDefault(x=>Mouse.x-tl.BoundingBox.left>x.left
    Mouse.x-tl.BoundingBox.left
    我认为您不必执行O(1)。O(1)假设每个附加字符都会对前面的所有字符产生影响,但事实并非如此。我最多只能看到一个O(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
    }
    
    IEnumerable TextLocations=。。。;
    内部类TextLocation
    {
    public RectF BoundingBox{get;set;}//这是相对于文本框的
    公共文本字文本字{get;set;}
    }
    内部类文本字
    {
    公共字符串文本{get;set;}
    公共IEnumerable字母{get;set;}
    }
    内部类LetterInfo
    {
    公共字符字母{get;set;}
    public float left{get;set;}//这些将是相对于边界框的
    public float right{get;set;}//不指向文本框
    }
    
    然后你可以做一些类似的事情

    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
        }                              
    }
    
    var tl=TextLocations.FirstOrDefault(x=>x.BoundingBox.Left鼠标.x
    &&x.BoundingBox.TopMouse.Y)
    如果(tl!=null)
    {
    //Text是单词(“the”,“Lazy”,“Dog…”)
    var字母=tl.TextWord.Letters
    .FirstOrDefault(x=>Mouse.x-tl.BoundingBox.left>x.left
    Mouse.x-tl.BoundingBox.left
    您必须将文本保存在文本框中,还是可以使用其他容器,如div?@Kris div是什么?我使用的是winforms,而不是HTML。请原谅,如果winforms中有这样的东西,我从来没有听说过。甚至听起来不像HTML问题,是winforms问题吗?邪恶的过早优化。鼠标是由人移动的。好的,您编辑了这个问题,使其包含winform标记和附加文本“for Windows Forms(因为RichTextBox很烂)”,也许下次你会在第一个问题中加上它,请不要让它听起来像我误读了这个问题。你必须把文本保存在文本框中还是可以使用其他容器,比如div?@Kris div是什么?我使用的是winforms,而不是HTML。请原谅,如果winforms中有这样的东西,我从来没有听说过。甚至听起来我都不知道ik