在给定像素偏移量的字符串中计算字符索引的最佳方法
本文关键字:计算 字符 索引 方法 最佳 字符串 像素 偏移量 | 更新日期: 2023-09-27 18:07:57
相关问题:基于像素偏移获取字符串索引
我知道这很接近那个问题,但这不是问如何直接做到这一点,而是问如何最好地做到这一点。
我正在实现我自己的Windows窗体的文本框(因为RichTextBox吸),我试图找到最好的方法,给定的字符串已经绘制在屏幕上,计算鼠标的字符。问题是字符可以是可变宽度的。
我想到了两种可能性:
-
执行
Graphics.MeasureCharacterRange
每次鼠标移动时,以二进制搜索方式在鼠标经过的行上(如顶部链接的问题所建议的) -
保存每行每个字符的偏移量列表
(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
}
}