Winform窗体程序 使用RichTextBox显示实时信息到窗体和保存记录到本地

目录

一.使用RichTextBox输出实时信息到窗体

二.保存输出记录到电脑本地文件夹中

三.在Winform界面查询RichTextBox控件输出的文本内容

 

 

一.使用RichTextBox输出实时信息到窗体

 不用重写RichTextBox控件,只需要继承自TextWriter类,它是一个抽象类。

这样做的主要目的是,当我们在程序的任何地方直接使用

 Console.WriteLine();

   Console.WriteLine()输出语句输出异常或者正常信息的时候,它都能够把实时信息显示在RichTextBox中

 首先窗体托入一个 RichTextBox控件

其次新建一个TextBoxWriter类

  public  class TextBoxWriter : System.IO.TextWriter
    {
        RichTextBox rtBox;
        delegate void VoidAction();

        public TextBoxWriter(RichTextBox box)
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            rtBox = box;
        }
        public override void WriteLine(string value)
        {
            VoidAction action = delegate
            {
                try
                {
                    //保存信息到文件夹
                    DbLogger.LogWrite(value);
                    string[] strLines = rtBox.Text.Split('\n');
                    if (strLines.Length > 1000)
                    {
                        rtBox.Clear();
                    }
                    if (!string.IsNullOrEmpty(value))
                    {
                        //让文本框获取焦点  
                        rtBox.Focus();
                        //设置光标的位置到文本尾  
                        rtBox.Select(rtBox.TextLength, 0);
                        //滚动到控件光标处  
                        rtBox.ScrollToCaret();
                        rtBox.AppendText(string.Format("\r\n[{0:HH:mm:ss}]{1}\r\n", DateTime.Now, value));
                       //更改颜色
                       rtBox.ForeColor = Color.FromArgb(51, 255, 102);
                    }
                    else
                    {
                        rtBox.AppendText("暂无日志");
                    }
                    

                }
                catch (Exception ex)
                {
                   DbLogger.LogException(ex,ex.Message);
                }

            };
            if (rtBox.IsHandleCreated)
            {
                try
                {
                    rtBox.BeginInvoke(action);
                }
                catch { }
            }

        }
        public override Encoding Encoding
        {
            get { return System.Text.Encoding.UTF8; }
        }

    }

接下来是最重要的一步,需要在窗体初始化时候,初始化

Console.SetOut(new TextBoxWriter(richTextBox1));//传入richTextBox1控件

 最后调用,打印输出实时信息到richTextBox1控件

 Console.WriteLine("Hello World!");

是的,只要在程序任何地方直接使用  Console.WriteLine()就能输出信息到richTextBox控件上。

 

二.保存输出记录到文件夹中

第一步,新建一个类项目:

在ClassLibrary1类库项目中,新建几个类,分别是LogRule (日志频率)LogLevel (日记级别)Logger (日记写入)DbLogger (日记调用)

 

 /// <summary>
    /// 日志频率
    /// </summary>
    public enum LogRule
    {
        Day,
        Hour,
        Minute,
        No
    }
 /// <summary>
    /// 日志级别
    /// </summary>
    public enum LogLevel
    {
        /// <summary>
        /// 程序运行记录,Debug模式
        /// </summary>
        AppTrace,

        /// <summary>
        /// 程序运行错误
        /// </summary>
        AppException,

        /// <summary>
        /// 一般运行信息,主要日志方式
        /// </summary>
        AppInfo,

        /// <summary>
        /// 运行警告,由开发人员记录
        /// </summary>
        AppWarn,

        /// <summary>
        /// 接口运行记录,Debug模式
        /// </summary>
        ApiTrace,

        /// <summary>
        /// 接口运行错误
        /// </summary>
        ApiException,

        /// <summary>
        /// 接口一般运行信息,主要日志方式
        /// </summary>
        ApiInfo,

        /// <summary>
        /// 接口运行警告,由开发人员记录
        /// </summary>
        ApiWarn,
        /// <summary>
        /// sql执行记录
        /// </summary>
        SqlTrace,
        /// <summary>
        /// 抽奖统计记录
        /// </summary>
        LuckTrace
    }
/// <summary>
    /// 日志写入
    /// </summary>
    public class Logger
    {
        /// <summary>
        /// 日志队列
        /// </summary>
        private static ConcurrentQueue<KeyValuePair<string, string>> _logQueue;

        /// <summary>
        /// 日志文件夹
        /// </summary>
        /// 
        private string _logPath = ConfigurationManager.AppSettings["LogPath"].ToString();
        private int _size;

        private Timer _watcher;

        #region Instance

        private static readonly object _lockObject = new object();
        private static volatile Logger _instance = null;

        /// <summary>
        /// 写日志,通过队列容量或定时触发写入操作
        /// </summary>
        /// <param name="capacity">记录数,默认为100</param>
        /// <param name="seconds">毫秒数,默认60秒</param>
        public Logger(int size = 100, int milliseconds = 60000)
        {
            //如果目录不存在则创建
            if (!Directory.Exists(this._logPath))
                Directory.CreateDirectory(this._logPath);

            _logQueue = new ConcurrentQueue<KeyValuePair<string, string>>();
            _size = size;

            _watcher = new Timer(milliseconds);
            _watcher.Elapsed += (o, e) =>
            {
                Submit();
            };
            _watcher.Start();
        }

        public static Logger Instance()
        {
            if (_instance == null)
            {
                lock (_lockObject)
                {
                    if (_instance == null)
                    {
#if DEBUG
                        _instance = new Logger(100, 3000);
#else
                        _instance = new Logger();
#endif
                    }
                }
            }
            return _instance;
        }

        #endregion

        #region 写日志

        /// <summary>
        /// 写日志 是一个入队操作
        /// </summary>
        /// <param name="str"></param>
        public void Write(string s, string prefix, LogRule rule = LogRule.Day)
        {
            if (string.IsNullOrWhiteSpace(s))
                return;

            DateTime dt = DateTime.Now;
            string val = string.Concat(dt, "\r\n", s);
            string key = string.Concat(prefix, GetKey(dt, rule));
            Write(key, val);
        }

        public void Write(string key, string val)
        {
            _logQueue.Enqueue(new KeyValuePair<string, string>(key, val));
            if (_logQueue.Count() >= _size)
                Submit();
        }

        /// <summary>
        /// 写日志 是一个入队操作
        /// </summary>
        /// <param name="str"></param>
        public void Write(string s, LogLevel level = LogLevel.AppInfo, LogRule rule = LogRule.Day, long ms = 0)
        {
            string prefix = level.ToString();
            if (ms > 0)
                ms = ms / 10 * 10;
            if (ms > 0)
                prefix = string.Concat("_", prefix, ms, "_");
            Write(s, prefix, rule);
        }
        #endregion

        #region 文本记录日志

        /// <summary>
        /// 写入文本记录
        /// </summary>
        public void Submit()
        {
            //独占方式,因为文件只能由一个进程写入.
            StreamWriter writer = null;
            var dict = GetLogText();
            string filename;
            FileInfo file;
            try
            {
                lock (_lockObject)
                {
                    foreach (var kv in dict)
                    {
                        filename = string.Concat(kv.Key, ".txt");
                        file = new FileInfo(this._logPath + "/" + filename);
                        //文件不存在就创建,true表示追加
                        writer = new StreamWriter(file.FullName, true, Encoding.UTF8);
                        writer.WriteLine(kv.Value);
                        writer.Close();
                    }
                }
            }
            finally
            {
                if (writer != null)
                    writer.Close();
            }
        }

        private string GetKey(DateTime dt, LogRule rule)
        {
            string key;
            switch (rule)
            {
                case LogRule.Minute:
                    key = dt.ToString("yyyyMMddHHmm");
                    break;
                case LogRule.No:
                    key = "";
                    break;
                case LogRule.Day:
                    key = dt.ToString("yyyyMMdd");
                    break;
                case LogRule.Hour:
                default:
                    key = dt.ToString("yyyyMMddHH");
                    break;
            }
            return key;
        }

        /// <summary>
        /// 得到日志文本 一个出队操作
        /// 将主键相同的数据拼接到一起,减少写入的io操作
        /// </summary>
        /// <returns></returns>
        private ConcurrentDictionary<string, string> GetLogText()
        {
            ConcurrentDictionary<string, string> dict = new ConcurrentDictionary<string, string>();
            string key, val;
            do
            {
                KeyValuePair<string, string> kv;

                if (_logQueue.TryDequeue(out kv))
                {
                    key = kv.Key;
                    val = string.Concat(kv.Value, "\r\n----------------------------------------\r\n");
                    dict.AddOrUpdate(key, val, (k, v) => string.Concat(v + "\r\n" + val));
                }
            } while (_logQueue.Count > 0);
            return dict;
        }
        #endregion
    }
 public static class DbLogger
    {
        public static void LogWrite(string context)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(string.Concat(context));
            Logger.Instance().Write(sb.ToString(), LogLevel.AppInfo);
        }
        public static void LogException(Exception ex, string lastCommand = null)
        {
            StringBuilder sb = new StringBuilder();

            if (!string.IsNullOrWhiteSpace(lastCommand))
                sb.AppendLine(string.Concat("LastCommand:", lastCommand));

            if (ex.InnerException != null)
                ex = ex.InnerException;

            sb.AppendLine(string.Concat("异常信息: " + ex.Message));
            sb.AppendLine(string.Concat("错误源:" + ex.Source));
            sb.AppendLine(string.Concat("堆栈信息:\r\n" + ex.StackTrace));

            Logger.Instance().Write(sb.ToString(), LogLevel.AppInfo);
        }
    }

重新编译解决方案,最后调用,在需要使用日记的项目里面引用ClassLibrary1类库

调用方式 1

DbLogger.LogWrite("Hello World!");

调用方式 2 

try
{
  //代码逻辑
}
catch (Exception ex)
 {
  DbLogger.LogException(ex, ex.Message);
  }

小技巧:

ConfigurationManager配置说明请查看:https://blog.csdn.net/weixin_39237340/article/details/92561824

private string _logPath = ConfigurationManager.AppSettings["LogPath"].ToString();

以上内容出忘记出自那了,项目里面用到,就拿来记录分享一下。如有侵权请联系本人,删除。 

 

三.界面RichTextBox控件查询输出的文本内容

RichTextBox控件查找文本演示,包括查找第一个/下一个/上一个/最后一个.
网上有很多方法,但是不能实现查询上一个功能。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

namespace vjsdn_tester
{
   //操作RichTextBox控件的类. by www.csframework.com
   public class RichTextBoxTool
   {
      /// <summary>
      /// 自己定义查找方法.参数content是要查询的内容.
      /// type是查询条件.如:从文件头部向下查询,从文件尾部向上查询.
      /// 如type= RichTextBoxFinds.None 表示从文件头部向下查询.
      /// </summary>
      public static void FindText(RichTextBox rich, string content, RichTextBoxFinds options)
      {
         int startIndex;
         int endIndex;
         
         if ((options & RichTextBoxFinds.Reverse) == RichTextBoxFinds.Reverse)
         {
            startIndex = 0;
            endIndex = rich.SelectionStart;
         }
         else
         {
            startIndex = rich.SelectionStart + rich.SelectionLength;
            endIndex = rich.Text.Length;
         }
         
         int index = rich.Find(content, startIndex, endIndex, options);
         
         if (index >= 0) //如果找到
         ShowSelection(rich, index, content.Length);
         else
         MessageBox.Show("Not found!");
      }
      
      //查找第一个
      public static void FindFirst(RichTextBox rich, string content)
      {
         int index = rich.Find(content, 0);
         if (index >= 0) ShowSelection(rich, index, content.Length);
      }
      
      //查找最后一个
      public static void FindLast(RichTextBox rich, string content)
      {
         int index = rich.Find(content, rich.Text.Length, RichTextBoxFinds.Reverse);
         if (index >= 0) ShowSelection(rich, index, content.Length);
      }
      
      //选择搜索到的文本
      private static void ShowSelection(RichTextBox rich, int index, int length)
      {
         rich.SelectionStart = index;
         rich.SelectionLength = length;
         rich.SelectionColor = Color.Red;
         rich.Focus();
      }
      
   }
}

测试代码调用

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

namespace vjsdn_tester
{
   public partial class frmRichboxSearher : Form
   {
      public frmRichboxSearher()
      {
         InitializeComponent();
      }
      
      //查找下一个单词
      private void btnFindNext_Click(object sender, EventArgs e)
      {
         string content = txtContent.Text;
         RichTextBoxTool.FindText(this.richTextBox1, content, RichTextBoxFinds.None);
      }
      
      //查找第一个单词
      private void btnFindFirst_Click(object sender, EventArgs e)
      {
         string content = txtContent.Text;
         RichTextBoxTool.FindFirst(this.richTextBox1, content);
      }
      
      //查找上一个单词
      private void btnFindPrior_Click(object sender, EventArgs e)
      {
         string content = txtContent.Text;
         RichTextBoxTool.FindText(this.richTextBox1, content, RichTextBoxFinds.Reverse);
      }
      
      //查找最后一个单词
      private void btnFindLast_Click(object sender, EventArgs e)
      {
         string content = txtContent.Text;
         RichTextBoxTool.FindLast(this.richTextBox1, content);
      }
   }
}

出自:http://www.csframework.com/archive/2/arc-2-20110716-1729.htm

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小丫头呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值