我想创建一个自动剪切长段的文本框区域(I want make a text box area that automatically cuts a long paragraph)

文本框区域自动将长段文本剪切成30个字符的句子我正在尝试运行此代码但发生异常[类型'System.StackOverflowException'的例外]

private void txtCutParagraph_TextChanged(object sender, EventArgs e) { int limitNum = 30; string sentence = txtCutParagraph.Text; string[] words = sentence.Split(' '); string line = ""; foreach (string word in words) { if ((line + word).Length > limitNum) { newLine += line + "\r\n"; line = ""; } line += word + " "; } if (line.Length > 0) newLine += line + "\r\n"; txtCutParagraph.Text = newLine; }

text box area that automatically cuts a long paragraph text into 30 characters sentences i am trying run this code but occurs exception [exception of type 'System.StackOverflowException']

private void txtCutParagraph_TextChanged(object sender, EventArgs e) { int limitNum = 30; string sentence = txtCutParagraph.Text; string[] words = sentence.Split(' '); string line = ""; foreach (string word in words) { if ((line + word).Length > limitNum) { newLine += line + "\r\n"; line = ""; } line += word + " "; } if (line.Length > 0) newLine += line + "\r\n"; txtCutParagraph.Text = newLine; }

最满意答案

你要做的是称为自动Word wrapping 。 TextBox类默认具有Wordwrap选项。 不幸的是,你不能限制每行的字符数。

你必须编写一个算法。 我注意到你的算法无法正常工作。 所以我决定写一个我自己(因为这是一个很好的做法!)。 很难处理文本格式化中可能发生的所有情况。 无论如何,如果你对结果不满意,我必须自己写一个。

在使用此算法之前,您必须禁用Textbox的Wordwrap功能。 所以他们不会互相干涉。 在Form Designer中的InitializeComponent中添加此行。

this.textBox1.WordWrap = false;

现在使用这个算法为你做! 请注意, textbox1是一个多行文本框。

private StringBuilder stringBuilder = new StringBuilder(); private bool _isInsideTextChanged = false; private const int MaximumChars = 30; // Maximum characters private StringBuilder WrapText(StringBuilder text, ref int position) { StringBuilder newStringBuilder = new StringBuilder(text.ToString()); int charsPerLine = 0; int lastSpace = -1; // index of last space per line for (int i = 0; i < newStringBuilder.Length; i++) { if (newStringBuilder[i] == ' ') { if (newStringBuilder.Length > i + 2 && newStringBuilder.ToString(i + 1, 2) == "\r\n") { if (newStringBuilder.Length > i + 3) { int next = newStringBuilder.ToString().IndexOf(' ', i + 3); if (next != -1 && charsPerLine + next - i <= MaximumChars || charsPerLine + newStringBuilder.Length - i - 2 <= MaximumChars) { newStringBuilder.Remove(i + 1, 2); if (i <= textBox1.SelectionStart) { position -= 2; } continue; } } i++; continue; } if (newStringBuilder.Length > i + 1 && newStringBuilder[i + 1] != ' ') { lastSpace = i; } } if (newStringBuilder[i] == '\n' || newStringBuilder[i] == '\r') { lastSpace = -1; charsPerLine = 0; } if (++charsPerLine > MaximumChars && lastSpace != -1) { newStringBuilder.Insert(lastSpace + 1, "\r\n"); if (lastSpace <= textBox1.SelectionStart) { position += 2; } charsPerLine = i - lastSpace; lastSpace = -1; i++; } } return newStringBuilder; } private void textBox1_TextChanged(object sender, EventArgs e) { if (_isInsideTextChanged) return; _isInsideTextChanged = true; stringBuilder.Clear(); stringBuilder.Append(textBox1.Text); int position = textBox1.SelectionStart; string newText = WrapText(stringBuilder, ref position).ToString(); textBox1.Text = newText; textBox1.SelectionStart = position; _isInsideTextChanged = false; }

这是显示结果的测试。

在此处输入图像描述

这怎么样?

此算法将计算从最后一个换行符索引(默认值为0)到每行最后一个空格字符索引的字符数。(默认值为-1表示该行中没有空格)。 然后,如果该行上的字符数超过30,它将在最后一个空格之后放置换行符。但是,此算法还测试其他内容以更好地处理文本格式。

每次更改文本框值时都会执行此操作。 StringBuilder而不是string来提高性能。

为了防止堆栈溢出异常,如@KhaksarWeqar所述,我使用了带有TextChanged事件的布尔值_isInsideTextChanged :

private bool _isInsideTextChanged = false; private void textBox1_TextChanged(object sender, EventArgs e) { if (_isInsideTextChanged) return; // return if was inside TextChanged. _isInsideTextChanged = true; // inside TextChanged // Do stuff... _isInsideTextChanged = false; // outside TextChanged }

在wiki上还有更好的解释方法。 你可以创造自己的更好! https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap

What you are trying to do is called Word wrapping. TextBox class has Wordwrap option by default. unfortunately you cant limit number of characters per line.

You have to write an algorithm instead. I have noticed that your algorithm does not work correctly. so i decided to write one my self (as it was a good practice!). It is hard to handle all situations that can happen inside text formatting. I tried my best anyway you have to write one your self if you are not satisfied with results.

Before using this algorithm you have to disable Wordwrap feature of Textbox. So they will not Interfere each other. In InitializeComponent inside Form Designer add this line.

this.textBox1.WordWrap = false;

Now use this algorithm to do it for you! Note that textbox1 is a multi line text box.

private StringBuilder stringBuilder = new StringBuilder(); private bool _isInsideTextChanged = false; private const int MaximumChars = 30; // Maximum characters private StringBuilder WrapText(StringBuilder text, ref int position) { StringBuilder newStringBuilder = new StringBuilder(text.ToString()); int charsPerLine = 0; int lastSpace = -1; // index of last space per line for (int i = 0; i < newStringBuilder.Length; i++) { if (newStringBuilder[i] == ' ') { if (newStringBuilder.Length > i + 2 && newStringBuilder.ToString(i + 1, 2) == "\r\n") { if (newStringBuilder.Length > i + 3) { int next = newStringBuilder.ToString().IndexOf(' ', i + 3); if (next != -1 && charsPerLine + next - i <= MaximumChars || charsPerLine + newStringBuilder.Length - i - 2 <= MaximumChars) { newStringBuilder.Remove(i + 1, 2); if (i <= textBox1.SelectionStart) { position -= 2; } continue; } } i++; continue; } if (newStringBuilder.Length > i + 1 && newStringBuilder[i + 1] != ' ') { lastSpace = i; } } if (newStringBuilder[i] == '\n' || newStringBuilder[i] == '\r') { lastSpace = -1; charsPerLine = 0; } if (++charsPerLine > MaximumChars && lastSpace != -1) { newStringBuilder.Insert(lastSpace + 1, "\r\n"); if (lastSpace <= textBox1.SelectionStart) { position += 2; } charsPerLine = i - lastSpace; lastSpace = -1; i++; } } return newStringBuilder; } private void textBox1_TextChanged(object sender, EventArgs e) { if (_isInsideTextChanged) return; _isInsideTextChanged = true; stringBuilder.Clear(); stringBuilder.Append(textBox1.Text); int position = textBox1.SelectionStart; string newText = WrapText(stringBuilder, ref position).ToString(); textBox1.Text = newText; textBox1.SelectionStart = position; _isInsideTextChanged = false; }

Here is the test that shows the results.

enter image description here

How this wroks?

This algorithm will count the number of characters from last line break index (default value is 0) up to last space character index per line.(default value is -1 means no space in that line). Then it will put line break after last space if the number of characters on that line is more than 30. How ever this algorithm test other things too to better handle text formatting.

This is done every time a textbox value is changed. StringBuilder is used instead of string to increase performance.

To prevent stack overflow exception as described by @KhaksarWeqar I used a boolean value _isInsideTextChanged with TextChanged event:

private bool _isInsideTextChanged = false; private void textBox1_TextChanged(object sender, EventArgs e) { if (_isInsideTextChanged) return; // return if was inside TextChanged. _isInsideTextChanged = true; // inside TextChanged // Do stuff... _isInsideTextChanged = false; // outside TextChanged }

There is also a better way explained on wiki. you can create your own even better!. https://en.wikipedia.org/wiki/Line_wrap_and_word_wrap

更多推荐