文本框区域,自动将长段文本剪切成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;
}
答案 0 :(得分:3)
如果表单冻结是因为txtCutParagraph_TextChanged
事件无限启动,因为您要在事件结束时更改textbox
的文本:txtCutParagraph.Text = newLine;
,所以这意味着更改文本框中的文本,事件将一次又一次地触发。
要防止此表单冻结,请将您的代码移至另一个文本框事件,名为KeyPress
:
private void txtCutParagraph_KeyPress(object sender, KeyPressEventArgs 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;
}
答案 1 :(得分:1)
您要做的是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所述,我使用了布尔值_isInsideTextChanged
和TextChanged
事件:
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