4

我正在使用代码编辑器(WinForms),我想知道如何执行 { 和 } 的功能,特别是使用括号(打开和关闭)的自动缩进,就像在实际代码编辑器中一样。

---|> { 和 }

像这样 1:

在此处输入图像描述

编辑器是一个名为 rtb 的富文本框。

4

2 回答 2

5

好的,我的解决方案有问题,但足以让您了解它的工作原理

我的结果:

{
        {
                {
                        }
                }
        }

这里是我的代码

public partial class Form1 : Form
{
    private bool FLAG_Selftimer = false;
    private bool FLAG_KeyPressed = false;
    private int pos = 0;
    public Form1()
    {
        InitializeComponent();
    }

    private void richTextBox1_TextChanged(object sender, EventArgs e)
    {
        var rtb = sender as RichTextBox;
        var point = rtb.SelectionStart;

        if (!FLAG_Selftimer)
        {
            rtb.Text = ReGenerateRTBText(rtb.Text);
            FLAG_KeyPressed = false;
        }
        else
        {
            point ++;
            FLAG_Selftimer = false;
        }

        rtb.SelectionStart = point;
    }



    private string ReGenerateRTBText(string Text)
    {
        string[] text = Regex.Split(Text,"\n");

        int lvl = 0;
        string newString = "";
        foreach (string line in text)
        {
            line.TrimStart(' ');
            newString += indentation(lvl) + line.TrimStart(' ') + "\n";
            if (line.Contains("{"))
                lvl++;
            if (line.Contains("}"))
                lvl--;
        }

        FLAG_Selftimer = true;
        return (!FLAG_KeyPressed) ? newString : newString.TrimEnd('\n');
    }

    private string indentation(int IndentLevel)
    {
        string space = "";
        if(IndentLevel>0)
            for (int lvl = 0; lvl < IndentLevel; lvl++)
            {
                    space += " ".PadLeft(8);
            }

        return space;
    }

    private void richTextBox1_KeyPress(object sender, KeyPressEventArgs e)
    {
        FLAG_KeyPressed = true;
    }
}

我希望这能帮到您

于 2013-05-08T09:09:10.017 回答
2

在阅读和使用代码之前,请阅读以下文本:

  1. 我没有足够的时间编写更好的代码。我只是尝试为您编写一个示例
  2. 我只是以简单的方式编写代码,而不是在 OOP 中
  3. 您可以使用EnumsPropertiesClassesOOP 的其他东西来改进代码。
  4. 您可以改进代码的逻辑;你可以使用多线程来实现更好的性能
  5. 这个样本不彻底。我只为 "分号 (;)" 字符实现了一个自动缩进示例

我应该说一些使用代码的提示:

  1. rtbCodes是示例项目中窗体上的 RichTextBox 控件的名称。
  2. frmCodeEditor是示例项目中表单的名称。

您可以从以下地址下载示例项目:

4Shared -> 代码编辑器的自动缩进

SendSpace -> 代码编辑器的自动缩进

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class frmCodeEditor : Form
    {
        char[] chrTracingKeyChars = new char[] { ';', '}', '\n' };
        char[] chrCheckingKeyChars = new char[] { '{', '(' };
        Point ptCurrentCharPosition;
        bool bolCheckCalling = false;
        int intInitialCursorPosition = 0;
        int intRemainingCharsOfInitialText = 0;
        int intNextCharIndex = 0;
        int intPrevCharIndex = 0;

        public frmCodeEditor()
        {
            InitializeComponent();
        }

        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            AutoIndention(rtbCodes);
        }

        /// <summary>
        /// Implements Auto-Indention.
        /// </summary>
        /// <param name="rtb">A RichTextBox control</param>
        private void AutoIndention(RichTextBox rtb)
        {
            char chrLastChar = GetChar(rtb);

            if (chrLastChar == chrTracingKeyChars[0])
            {
                intRemainingCharsOfInitialText = rtb.TextLength - rtb.SelectionStart;
                intInitialCursorPosition = rtb.SelectionStart;
                ImplementIndentionForSemicolon(rtb);
            }
            else if (chrLastChar == chrTracingKeyChars[1])
            {
                ImplementIndentionForRightCurlyBracket(rtb);
            }
            else if (chrLastChar == chrTracingKeyChars[2])
            {
                ImplementIndentionForNewLineCharacter(rtb);
            }
        }

        /// <summary>
        /// Specifies current char based on the cursor position.
        /// </summary>
        /// <param name="rtb">A RichTextBox control</param>
        /// <returns>Returns a char.</returns>
        private char GetChar(RichTextBox rtb)
        {
            return GetChar(rtb.SelectionStart, rtb);
        }

        /// <summary>
        /// Specifies a char based on the specified index.
        /// </summary>
        /// <param name="intCharIndex">A char index</param>
        /// <param name="rtb">A RichTextBox control</param>
        /// <returns>Returns a char.</returns>
        private char GetChar(int intCharIndex, RichTextBox rtb)
        {
            if (intCharIndex != rtb.TextLength)
            {
                ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex - 1);
            }
            else
            {
                ptCurrentCharPosition = rtb.GetPositionFromCharIndex(intCharIndex);
            }
            return rtb.GetCharFromPosition(ptCurrentCharPosition);
        }

        /// <summary>
        /// Specifies current line number based on the cursor position.
        /// </summary>
        /// <param name="rtb">A RichTextBox control</param>
        /// <returns>Returns the line number.</returns>
        private int GetLineNumber(RichTextBox rtb)
        {
            return GetLineNumber(rtb.GetFirstCharIndexOfCurrentLine(), rtb);
        }

        /// <summary>
        /// Specifies the line number based on the specified index.
        /// </summary>
        /// <param name="intCharIndex">A char index</param>
        /// <param name="rtb">A RichTextBox control</param>
        /// <returns>Returns the line number.</returns>
        private int GetLineNumber(int intCharIndex, RichTextBox rtb)
        {
            return rtb.GetLineFromCharIndex(intCharIndex);
        }

        /// <summary>
        /// Implements indention for semicolon ";" character.
        /// </summary>
        /// <param name="rtb">A RichTextBox control</param>
        private void ImplementIndentionForSemicolon(RichTextBox rtb)
        {
            Dictionary<char, int> dicResult = IsExistCheckingKeyChars(rtb);
            if (dicResult[chrCheckingKeyChars[0]] != -1)
            {
                int intIndentionLevel = CheckingIndentionLevel(dicResult[chrCheckingKeyChars[0]], rtb);
                ImplementIndention(dicResult[chrCheckingKeyChars[0]], intIndentionLevel, rtb);
            }
        }

        private void ImplementIndentionForRightCurlyBracket(RichTextBox rtb)
        {

        }

        private void ImplementIndentionForNewLineCharacter(RichTextBox rtb)
        {

        }

        /// <summary>
        /// Checks current and previous lines for finding key-chars.
        /// </summary>
        /// <param name="rtb">A RichTextBox control</param>
        /// <param name="bolSearchCurrentLine">The search state</param>
        /// <returns>Returns first occurrences of key-chars before current char.</returns>
        private Dictionary<char, int> IsExistCheckingKeyChars(RichTextBox rtb, bool bolSearchCurrentLine = false)
        {
            GetChar(rtb);

            Dictionary<char, int> dicCheckingKeyCharsIndexes = new Dictionary<char, int>();
            for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++)
            {
                dicCheckingKeyCharsIndexes.Add(chrCheckingKeyChars[intCntr], 0);
            }

            for (int intCntr = 0; intCntr < chrCheckingKeyChars.Length; intCntr++)
            {
                int intFirstIndexForChecking = 0;
                int intLastIndexForChecking = 0;
                for (int intLineCounter = GetLineNumber(rtb); intLineCounter >= 0; intLineCounter--)
                {
                    if (intLineCounter == GetLineNumber(rtb))
                    {
                        intLastIndexForChecking = rtb.GetCharIndexFromPosition(ptCurrentCharPosition);
                    }
                    else
                    {
                        intLastIndexForChecking = intFirstIndexForChecking - 1;
                    }
                    intFirstIndexForChecking = rtb.GetFirstCharIndexFromLine(intLineCounter);

                    try
                    {
                        dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking,
                            rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None);
                        if (dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] != -1)
                        {
                            do
                            {
                                if (rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking, rtb.GetCharIndexFromPosition(ptCurrentCharPosition),
                                    RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None) != -1)
                                {
                                    dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = rtb.Find(chrCheckingKeyChars[intCntr].ToString(), intFirstIndexForChecking,
                                        rtb.GetCharIndexFromPosition(ptCurrentCharPosition), RichTextBoxFinds.NoHighlight | RichTextBoxFinds.None);
                                }
                                intFirstIndexForChecking++;
                            } while (intFirstIndexForChecking != rtb.GetCharIndexFromPosition(ptCurrentCharPosition));
                            break;
                        }
                    }
                    catch
                    {
                        dicCheckingKeyCharsIndexes[chrCheckingKeyChars[intCntr]] = -1;
                        break;
                    }

                    if (bolSearchCurrentLine)
                    {
                        break;
                    }
                }
            }

            return dicCheckingKeyCharsIndexes;
        }

        /// <summary>
        /// Checks a line for calculating its indention level.
        /// </summary>
        /// <param name="intCharIndex">A char index</param>
        /// <param name="rtb">A RichTextBox control</param>
        /// <returns>Returns indention level of the line.</returns>
        private int CheckingIndentionLevel(int intCharIndex, RichTextBox rtb)
        {
            int intLineNumber = GetLineNumber(intCharIndex, rtb);
            int intIndentionLevelNumber = 0;

            intCharIndex = rtb.GetFirstCharIndexFromLine(intLineNumber);
            char chrChar = GetChar(intCharIndex, rtb);
            if (chrChar == '\n')
            {
                chrChar = GetChar(++intCharIndex, rtb);
            }

            if (chrChar != ' ')
            {
                return 0;
            }
            else
            {
                int intSpaceCntr = 0;
                while(chrChar == ' ')
                {
                    chrChar = GetChar(++intCharIndex, rtb);
                    if (chrChar == ' ')
                    {
                        intSpaceCntr++;
                    }

                    if (intSpaceCntr % 4 == 0 && intSpaceCntr != 0)
                    {
                        intIndentionLevelNumber++;
                        intSpaceCntr = 0;
                    }
                }

                if (intSpaceCntr % 4 != 0)
                {
                    intIndentionLevelNumber++;
                }
            }

            return intIndentionLevelNumber;
        }

        /// <summary>
        /// Implements Indention to the codes
        /// </summary>
        /// <param name="intCharIndex">A char index</param>
        /// <param name="intIndentionLevel">The number of indention level</param>
        /// <param name="rtb">A RichTextBox control</param>
        private void ImplementIndention(int intCharIndex, int intIndentionLevel, RichTextBox rtb)
        {
            intNextCharIndex = intCharIndex;

            intPrevCharIndex = intCharIndex;
            int intKeyCharsNumberInLine = 1;
            int intCurrentLineNumber = GetLineNumber(rtb);
            int intKeyCharLineNumber = GetLineNumber(intNextCharIndex, rtb);
            string[] strLinesTexts;
            Dictionary<char, int> dicResult;

            do
            {
                rtb.SelectionStart = intPrevCharIndex;
                dicResult = IsExistCheckingKeyChars(rtb);
                if (dicResult[chrCheckingKeyChars[0]] != -1)
                {
                    intKeyCharsNumberInLine++;
                    intPrevCharIndex = dicResult[chrCheckingKeyChars[0]];
                }
            } while (dicResult[chrCheckingKeyChars[0]] != -1);

            if (!bolCheckCalling)
            {
                if (intCurrentLineNumber == intKeyCharLineNumber)
                {
                    for (int intCntr = 1; intCntr <= intKeyCharsNumberInLine; intCntr++)
                    {
                        do
                        {
                            rtb.SelectionStart = intPrevCharIndex;
                            dicResult = IsExistCheckingKeyChars(rtb, true);
                            if (dicResult[chrCheckingKeyChars[0]] != -1)
                            {

                                intPrevCharIndex = dicResult[chrCheckingKeyChars[0]];
                            }
                        } while (dicResult[chrCheckingKeyChars[0]] != -1);

                        bolCheckCalling = true;
                        ImplementIndention(intPrevCharIndex, rtb);
                    }
                    return;
                }
            }

            bolCheckCalling = false;
            rtb.SelectionStart = intNextCharIndex;
            rtb.SelectionLength = 1;
            rtb.SelectedText = "\n" + rtb.SelectedText;
            intCurrentLineNumber = GetLineNumber(rtb);

            strLinesTexts = rtb.Lines;
            strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim();

            for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel; intIndentionCntr++)
            {
                for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++)
                {
                    strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber];
                }
            }
            rtb.Lines = strLinesTexts;

            rtb.SelectionStart = intNextCharIndex + ((intIndentionLevel * 4) + 1);
            intNextCharIndex = rtb.SelectionStart;
            rtb.SelectionLength = 1;
            rtb.SelectedText = rtb.SelectedText + "\n";
            intCurrentLineNumber = GetLineNumber(rtb);

            strLinesTexts = rtb.Lines;
            strLinesTexts[intCurrentLineNumber] = strLinesTexts[intCurrentLineNumber].Trim();

            for (int intIndentionCntr = 1; intIndentionCntr <= intIndentionLevel + 1; intIndentionCntr++)
            {
                for (int intSpaceCntr = 1; intSpaceCntr <= 4; intSpaceCntr++)
                {
                    strLinesTexts[intCurrentLineNumber] = ' ' + strLinesTexts[intCurrentLineNumber];
                }
            }
            rtb.Lines = strLinesTexts;
            rtb.SelectionStart = intInitialCursorPosition + ((rtb.TextLength - intInitialCursorPosition) - intRemainingCharsOfInitialText);
            intNextCharIndex = rtb.SelectionStart;
            intPrevCharIndex = intNextCharIndex;
        }

        /// <summary>
        /// Implements Indention to the codes
        /// </summary>
        /// <param name="intCharIndex">A char index</param>
        /// <param name="rtb">A RichTextBox control</param>
        private void ImplementIndention(int intCharIndex, RichTextBox rtb)
        {
            int intIndentionLevel = CheckingIndentionLevel(intCharIndex, rtb);
            ImplementIndention(intCharIndex, intIndentionLevel, rtb);
        }
    }
}

我希望这个示例代码可以帮助你。

如果您改进它们,请更新和共享代码。

于 2013-07-24T08:53:08.213 回答