我想创建一个自动剪切长段的文本框区域

时间:2015-10-11 04:15:50

标签: c# winforms

文本框区域,自动将长段文本剪切成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;
}

2 个答案:

答案 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 wrappingTextBox类默认具有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;
}

以下是显示结果的测试。

enter image description here

这是怎么回事?

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

每次更改文本框值时都会执行此操作。使用StringBuilder代替string来提高效果。

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

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