为文本编辑控件实现缓冲区的最佳方法是啥?
Posted
技术标签:
【中文标题】为文本编辑控件实现缓冲区的最佳方法是啥?【英文标题】:What is the best way to implement a buffer for a text edit control?为文本编辑控件实现缓冲区的最佳方法是什么? 【发布时间】:2011-11-12 06:26:25 【问题描述】:所以我正在制作一个自定义编辑控件。为了跟踪编辑控件的内容,我使用了一个动态分配的 char 数组。
现在,我知道我需要在数组中间插入 某些情况,例如当用户点击特定的 观点。所以,我在想,而不是字符数组,我可以使用 std::vector,所以我可以使用 .insert 函数,而且 不必太在意内存管理。 我也在考虑可能将输入流直接存储到 单词数组/向量(不保持连续缓冲区),因为我的 这样做的全部目的是实现语法高亮。哪种处理方式更好?为什么?
【问题讨论】:
【参考方案1】:对于当今计算机的文本缓冲区,您确实可以只使用单个连续缓冲区(例如向量),因为 CPU 速度足够快,可以缩短插入时间(使用这种幼稚方法的 o(n)
操作)仍然是一个可行的选择。
在过去,当计算机速度慢数千倍时,一种常见的简单方法是将文本保存在缓冲区中,但有一个与光标位置相对应的“洞”,以便插入 o(1)
操作并从一个移动字符当光标在文本中移动时,孔的一侧到另一侧(基本上使光标移动成为o(k)
操作,其中k
是跳过的字符数)。
对于为程序员设计的编辑器,文本将被细分为逻辑行,因此使用基于行指针数组的方法似乎是合适的。即使这会使一些跨线操作有点烦人,一些基于行的操作会变得更容易......显示中的行号成为一个微不足道的问题,特别是如果你不需要实现换行(无论如何代码都很糟糕)通过截断和水平滚动来代替。
【讨论】:
这是一个非常好的解释,谢谢!是的,文本将被分成逻辑行,我将使用水平滚动。 使用一个连续缓冲区的编辑器在编辑大量文件(例如日志文件)时会遭受可怕的损失。对于源文件,这很好,但人们不可避免地希望在他们的编辑器中加载 everything。因此需要进行某种细分。【参考方案2】:最好的方法是从系统编辑或richedit控件开始,并根据您的需要进行调整。编写自己的编辑控件比您可能意识到的要多得多 - 包括处理可访问性、用于具有复杂字母的语言的 IME、复制和粘贴、滚动条、光标、选择等等。
这两个系统控件提供了许多扩展点,可以让您实现大多数目标。除非您真的在构建文字处理程序或源代码编辑器,否则您应该坚持使用提供的那些。自定义编辑控件是大量错误来源。我很少看到一种只适用于基本情况的方法。
马丁
【讨论】:
我正在构建一个源代码编辑器。我已经尝试过richedit,并且对它进行子类化并没有我想要的那么快。我使用了 over-write 和 setcharformat 方法,但它们不是很整洁,可以这么说。我已经开始使用自定义编辑控件,并且已经实现了光标和多行输入。所以,现在我正在尝试让它为文本选择和多行选择和其他东西做好准备 如果你真的在构建一个源代码编辑器,那么实现你自己的缓冲区是正确的想法。大多数源代码编辑器都被要求加载非常大的文件(例如服务器日志),因此请务必认真考虑基本操作的大 O 可扩展性。【参考方案3】:如果您正在考虑使用可变后备存储的源代码查看器(参考:“实现语法突出显示”),您可能会发现std::list<std::string>
是一个很好的起点,如果字符串很小,它可能会过大.
使用连续的文本缓冲区(例如,一个大的 std::string
或 std::vector
),您将在编辑期间进行大量移动和调整大小,以及在重新定位时进行大量扫描。这些移动和调整大小将导致许多大的、连续的分配、缓冲区的初始化、移动和旧内存的释放。它还限制了您缓存数据的方式(如果这很重要)。使用列表查找时间会稍微慢一些,但您的移动和突变会比对整个文件使用连续缓冲区快得多。
std::list<std::string>
有一些很好的属性,因为它作为字符串的集合(例如,对于每一行或每一段)很好地增长和变异。
此概述详细介绍了该列表的优势并将其与其他容器进行了很好的比较:http://www.cplusplus.com/reference/stl/list/
如果你想将一些数据关联到字符串/行,那么只需创建一个列表:
namespace MON
class t_line
public:
/* ... */
private:
std::string d_string;
t_lexer_stuff d_lexerStuff;
;
【讨论】:
【参考方案4】:在搜索同一篇文章时,我发现了两个非常有帮助的***页面:
Gap buffer 用于简单编辑
Rope (data structure) 用于复杂的文本编辑
【讨论】:
我在 cpp 中的间隙缓冲区尝试:github.com/cmaughan/gapbuffer【参考方案5】:您可能需要双重表示,因此同时具有 char 向量和单词向量(问题是要使它们保持同步)。
我建议你也看看,甚至可能使用一些图形工具包,其源代码是免费的,并且可以定制。 (我不是 Windows 人,但是)我在想例如Qt 是一个开源的 C++ 图形库,在 Windows、Linux、MacOSX 上运行...
我无能为力,因为我不知道而且我不使用 Windows(我所有的机器都在 Linux 下)。
【讨论】:
感谢您的回复!一旦我完成了自己的事情,我肯定会调查他们。我想先了解所有“幕后”的东西。我还认为可能需要双重代表。这会对性能/内存使用产生影响吗?以及如何保留一个字符向量和每个单词的位置向量?喜欢起始位置和长度(使用结构)?那会是更好的性能吗? 过早的优化是邪恶的所以首先编写一个正确的实现,使用分析器对其进行基准测试,然后对其进行优化 实际上,我只是想了解我应该使用代码的地方,这样我就不会浪费时间,因为选择正确的方法可以很容易地避免它问题 @Basile,选择正确的数据表示并不是过早的优化。如果您盲目地选择数据结构和算法,您很容易发现自己的系统无法工作。以上是关于为文本编辑控件实现缓冲区的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
将富编辑控件中的整个文本作为 CString 获取的各种方法