C#使用Winform实现简单的编辑器:编译、运行、关键字、注释高亮显示。

发布文章的目的即是学习也是分享保存。

 

  • 目录

1、简单的界面设计
2、实现代码
  (1)用到的变量字段
  (2)窗体初始化、加载
  (3)执行操作:编译、运行
  (4)编译功能方法
  (5)高亮显示
  (6)其它
3、运行效果
4、说明
(1)文本发生变化的重绘滚动(闪烁)问题。
(2)光标位置显示问题。
(3)关键字高亮显示后,直接在后面输入文字格式问题。


1、简单的界面设计

  程序分为脚本编辑框,操作、结果显示栏。 脚本编辑栏:可以编写自己想要的代码。
  操作栏:其中脚本操作可以手动导入代码,也可以导出代码。预选为.txt文本格式,和支持其他格式。导出功能可以导出代码,保存格式只设置了.txt格式。
  结果栏:点击编译显示编译结果,点击运行显示运行结果,填入命名空间、类名、方法可以简单显示指定的方法结果(建议是复制到文本框中,否则可能会报错)。

 

2、实现代码

 

(1)用到的变量字段

复制代码
/// CSarpe关键字
private string[] _keyWords = { "abstract", "as", "base", "bool", 
"break", "byte", "case","catch","char", "checked", "class", "const", 
"continue", "decimal", "default","delegate", "do", "double", "else", 
"enum", "event", "explicit", "extern","false", "finally", "fixed", 
"float", "for", "foreach", "goto", "if", "implicit","in", "int", 
"interface", "internal", "is", "lock", "long", "namespace", "new",
"null", "object", "operator", "out", "override", "params", "partial", "private",
"protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short",
"sizeof", "stackalloc", "static", "string", "struct", "switch", "this", "throw",
"true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using",
"virtual", "void", "volatile", "while","get","set" };

/// 选择文件
private OpenFileDialog openFileDialog1 = new OpenFileDialog();

/// 编译结果
CompilerResults Result = null;

/// 用于判断特殊按键不做rtb文本发生变化事件处理(如:Enter键、Table键)
bool isEnter = false;
复制代码

 

 

(2)窗体初始化、加载

 

复制代码
public Form1()
{
    InitializeComponent();
    this.MaximumSize = new System.Drawing.Size(760, 650);
    this.MinimumSize = new System.Drawing.Size(760, 650);
    this.rtbScriptCode.KeyDown += 
    new System.Windows.Forms.KeyEventHandler(this.rtbKeyDownEnter);
}
private void Form1_Load(object sender, EventArgs e)
{
    rtbScriptCode.Multiline = true;
    rtbScriptCode.WordWrap = true;
}
复制代码

(3)执行操作:编译、运行

 

复制代码
/// 点击编译按钮
private void btnCompile_Click(object sender, EventArgs e)
{
    if (rtbScriptCode.Text.ToString().Trim().Length < 1) 
    { 
        AppendInfo("Code Null"); return; 
    }
    CompileCode();
    CompilerEffect();
}
/// 点击运行按钮
private void btn02Run_Click(object sender, EventArgs e)
{
     if (rtbScriptCode.Text.ToString().Trim().Length < 1) 
     { AppendInfo("Code Null"); return; }
    CompileCode();
    // 通过反射,调用实例 
    if (Result != null)
    {
        if (tbNamespace.Text.Trim().Length < 1 || 
            tbMethodName.Text.Trim().Length < 1) return;
        try
        {
             AppendInfo("开始运行.....");
             Assembly objAssembly = Result.CompiledAssembly;
             object objHelloWorld = 
             objAssembly.CreateInstance($"{tbNamespace.Text}.{tbClassName.Text}");
             MethodInfo objMI = objHelloWorld.GetType().GetMethod(tbMethodName.Text);
             object ReValue = objMI.Invoke(objHelloWorld, null);
             AppendInfo(ReValue);
        }
        catch (Exception ex)
        {
            AppendInfo("编译失败:");
            AppendInfo(ex.Message);
        }
    }
        else{    MessageBox.Show("执行未编译代码!");    }
}
复制代码

(4)编译功能方法

复制代码
public void CompileCode()
{
      AppendInfo("编译开始.....");
      //【1】新建C#代码生成器和代码编译器的实例
      CodeDomProvider Provider = CodeDomProvider.CreateProvider("CSharp");
      //【2】配置用于调用编译器的参数
      CompilerParameters Parameters = new CompilerParameters();
      Parameters.ReferencedAssemblies.Add("System.dll");
      Parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
      Parameters.ReferencedAssemblies.Add("System.Linq.dll");
      Parameters.GenerateExecutable = false;
      Parameters.GenerateInMemory = true;
      //【3】启动编译
      Result = Provider.CompileAssemblyFromSource(Parameters, rtbScriptCode.Text);
      if (Result.Errors.HasErrors)
      {
            AppendInfo("编译错误:");
            foreach (CompilerError err in Result.Errors)
            {
                 AppendInfo(err.ErrorText);
            }
    }
    else
    {
        AppendInfo("编译成功。");
    }              
}
复制代码

(5)高亮显示

复制代码
/// 关键字高亮效果
private void HighlightKeywords()
{
    rtbScriptCode.Font = new Font("Consolas", 12);
    foreach (string keyword in _keyWords)
    {
        int startIndex = 0; //索引
        //小于文本长度
        while (startIndex < rtbScriptCode.TextLength)
        {
            //仅定位关键字全字的搜索索引
            int index = rtbScriptCode.Find(keyword, startIndex, RichTextBoxFinds.WholeWord);
            if (index == -1) break;
            rtbScriptCode.SelectionStart = index;
            rtbScriptCode.SelectionLength = keyword.Length;
            rtbScriptCode.SelectionColor = Color.Blue;
            startIndex = index + keyword.Length;
        }
    }
}
 /// 注释高亮效果
private void HighlightComments()
{
    // 使用正则表达式查找所有注释,并将其文本颜色设置为灰色
    Regex regex = new Regex(@"(?://.*?$|/\*.*?\*/)",
                      RegexOptions.Multiline | RegexOptions.Singleline);
    MatchCollection matches = regex.Matches(rtbScriptCode.Text);
    int startIndex = rtbScriptCode.SelectionStart;
    int length = rtbScriptCode.SelectionLength;
    foreach (Match match in matches)
    {
        rtbScriptCode.Select(match.Index, match.Length);
        rtbScriptCode.SelectionColor = Color.Green;
    }
    rtbScriptCode.Select(startIndex, length);
}
/// 调用方法高亮显示
public void CompilerEffect()
{
    HighlightKeywords();
    HighlightComments();
}
/// 文本发生改变
private void rtbScriptCode_TextChanged(object sender, EventArgs e)
{
    int index = rtbScriptCode.SelectionStart; //插入位置
    if (!isEnter)
    {
        CompilerEffect();
        if (index != -1)
        {
            rtbScriptCode.SelectionStart = index;
            rtbScriptCode.SelectionLength = 0;
        }
        return;
    }
}
复制代码

 

(6)其它

复制代码
/// Table键效果
private void rtbScriptCode_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Tab && !(rtbScriptCode.ReadOnly) && !(rtbScriptCode.Enabled))
    {
        int selectionStart = rtbScriptCode.SelectionStart;
        rtbScriptCode.SelectedText = "\t";
        rtbScriptCode.SelectionStart = selectionStart + 1;
        e.SuppressKeyPress = true;
    }
}
/// 文本框中指定按下指定键,不进行关键字高亮操作(高亮操作导致重画会)
private void rtbKeyDownEnter(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab || e.KeyCode == Keys.Space) 
    isEnter = true;
    else isEnter = false;
}

/// 文本域鼠标右键
private void rtbScriptCode_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button.ToString().Equals("Right")) rtbScriptCode.SelectAll();
}

/// 追加字符
private void AppendInfo(object Info)
{
    tb01CompileResult.Text = Info + "\n\r";
}

/// 导出代码
private void btn03Save_Click(object sender, EventArgs e)
{
    if ((rtbScriptCode.Text.Trim().Length) < 1) return;
    string fileName = tbFileName.Text;
    string path = @"C:\Users\qin\Desktop\TeseCompile\" + $"{fileName}{labelFilePostfix.Text}";
    //确认保存,保存方式
    bool saveMethod = false;
    //保存文件
    if (DialogResult.Yes == MessageBox.Show(path, "保存", MessageBoxButtons.YesNo))
    {
        if (File.Exists(path))
        {
            //是否替换文件
            if (DialogResult.Yes == 
                MessageBox.Show("是否替换文件", "替换", MessageBoxButtons.YesNo))
                saveMethod = false;
            else
            {
                int i = 1;
                while (File.Exists(path))
                {
                    tbFileName.Text = fileName + i.ToString();
                    i++;
                    path = @"C:\Users\qin\Desktop\TeseCompile\" + 
                           $"{tbFileName.Text}{labelFilePostfix.Text}";
                    saveMethod = true;
                }
            }
        }
        //保存
        using (StreamWriter writer = new StreamWriter(path, saveMethod))
        {
        writer.Write(rtbScriptCode.Text);
        MessageBox.Show($"文件:{tbFileName.Text}{labelFilePostfix.Text}保存成功!");
        }
    }
}

/// 导入文件
private void btnImportCode_Click(object sender, EventArgs e)
{
    OpenFileDialog fileDialog = new OpenFileDialog();
    fileDialog.Multiselect = true;
    fileDialog.Title = "请选择文件";
    fileDialog.Filter = "文本文件(*.txt)|*.txt; | 所有文件(*.*)|*.*";
    if (fileDialog.ShowDialog() == DialogResult.OK)
    {
        rtbScriptCode.Text = "";
        string file = fileDialog.FileName;
        string fileName = fileDialog.SafeFileName;
        tbFileName.Text = fileName.Substring(0, fileName.Length - ".txt".Length);
        using (StreamReader read = new StreamReader(file))
        {
            string line = "";
            while ((line = read.ReadLine()) != null)
            {
                rtbScriptCode.AppendText(line + "\r\n");
            }
        }
    }
    rtbScriptCode.SelectionLength = rtbScriptCode.Text.Length;
    CompilerEffect();
}
复制代码

 

3、运行效果

代码导入

运行效果

4、说明

2023-06-04
程序的不完善:

1、文本发生变化的重绘滚动(闪烁)问题。
程序中,使用RichTextBox控件编辑代码,每键入一个字符,都会触发文本变化事件,而关键字高亮显示是在文本发生变化后重绘的,所以会出现编写代码时存在闪烁问题。
测试发现如果不是导入的代码,不会发生闪烁问题(测试输入十行)。 测试编译时文本高亮显示无问题。

2、光标位置显示问题。
程序中,在导入代码后开始编辑,会发生类似滚动的现象(跟鼠标滚动一样)。 光标(焦点)跑位已解决。

3、关键字高亮显示后,直接在后面输入文字格式问题。
关键字后面的文本格式会跟关键字一样。
————————————————
                        
(本人)原文链接:https://blog.csdn.net/weixin_43626218/article/details/131032962

 

posted @   吾与谁归  阅读(36)  评论(0编辑  收藏  举报
编辑推荐:
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· spring官宣接入deepseek,真的太香了~
点击右上角即可分享
微信分享提示