从头开始的基本文本框

本文关键字:文本 从头开始 | 更新日期: 2023-09-27 18:21:20

我想试试我自己的简单TextBox控件。我不太确定它们是如何编写的,但我看了一下Windows窗体TextBox的参考源,它只是添加了更多的问题,所以我想我会问自己的问题,这些问题是基于我如何思考创建TextBox控件:

字符/文本是如何绘制的?由于我将从头开始创建TextBox,因此我显然需要绘制。因此,当你在WinForms中绘制东西时,你不能只选择文本,你需要处理MouseDown和MouseMove事件,获得鼠标被按下的位置,然后确定哪个角色(如果有的话)在那个位置。但除非我们把这个角色和它的坐标一起保存在某个地方,否则我们真的无法做到这一点。这意味着我们可能需要使用一个列表来存储用户键入的所有内容:

List<Character> characters = new List<Character>();
class Character
{
    public string Text { get; set; }
    public Location { get; set; }
    public Size { get; set; }
}

现在我们已经知道了这个字符的位置,我们需要画一个填充的矩形,这样用户就知道他们在选择什么。我们可以通过在之前确定的坐标处获取角色的大小和位置来实现这一点。

TextBox基本上就是这样工作的吗?

1) 当用户键入内容时,我们使用DrawString来绘制"键入"的内容,然后将其大小和位置存储在列表中以供将来参考?2) 当用户"选择"文本时,我们查找用户在列表中"选择"的坐标,然后在该位置绘制一个填充矩形?

从头开始的基本文本框

我确实编写了自己的WinForms TextBox(以满足在数据输入期间进行拼写检查的需要,并通过字体下划线和颜色突出显示错误拼写)。在我对此进行调查的过程中,我发现.net本身并没有实现文本框渲染(它是一个Windows功能),所以不得不从头开始发明。

我的方法与您的方法非常相似,但需要记住的重要一点是,没有一个数据结构足以存储文本框的所有内容。具体而言,文本框应包含以下内容的集合;

  1. 字符列表
  2. TextRuns是共享同一演示文稿的所有字符(如字体、颜色等)的字符列表的索引。通常情况下,TextRuns比characters少
  3. 一个高亮显示文本Run记录用户当前高亮显示的字符
  4. Carat位置-这可能很棘手。文本框carat可以在第一个字符之前,也可以在最后一个字符之后,也可以是介于两者之间的任何字符
  5. 最后一个绘制的文本框的图像,就像一个缓冲区,这样OnPaint消息就可以在不重复MeasureString和DrawString调用的情况下快速得到满足。在多行或可滚动框的情况下,这通常会大于TextBox的可渲染区域,在这种情况下,您可以根据请求渲染矩形子集
  6. RenderRun列表,表示一组字符的位置和大小,所有字符都在同一个TextRun中,绘制在同一文本框行上,是绘制的基本单元。RenderRun将在图像中具有偏移位置和大小,使您能够为图像中的任何给定位置选择正确的RenderRun。后续选择特定字符将需要为RenderRun中的每个字符提供MeasureString。可以选择将角色大小存储在RenderRun中,也可以在每次需要时动态计算

这一切的结果就是

  • 自定义文本框明显比Windows原生文本框慢
  • 这需要更多的记忆

所以我们只在需要拼写检查的字段中使用它。

最终,我建议不要尝试它,因为尽管总体"感觉"可能是它不是一个原生的Windows文本框,而且它的行为非常微妙地不同(尤其是它的滚动方式——按像素而不是按行)。

希望这能有所帮助。