[原创]ConsoleApplication ProgressBar

很抱歉各位看官,不太会排版丑陋了点,但是重点很清晰。

 

因本人的工作原因,大部分时间都在和控制台打交道,话说无论写什么控制台处理程序都有进度显示,方便直观。假设如果仅使用文件方式记录进度的话相当的麻烦,当然这个用作记录日志的话另当别论了。本文为了方便查看处理进度而特意在ConsoleApplication ProgressBar花了1个小时而开发的一个进度条控件类。

 

首先例举两个个常用的记录进度方式:

1、Console.Write

如图:

这种是最常见的,没什么好不好之说,但是不好的地方显而易见:屏幕一刷而过,当有其他的信息需要打印的时候还得翻滚动条。如果进度太长就无奈了。

2、Console.Title

如图:

 

这个用的相对比较少,如果开的比较多控制台的话,Title上原本的信息就没有了。

3、ConsoleApplication ProgressBar

如图:

 

 

综合前面两种方式,后者是最为方便的。好处我想不用我多说了。

 

下面奉上源码

 

调用示例:

class Program
    {
        static void Main(string[] args)
        {
            Random r = new Random();
            while (true)
            {
                ConsoleProgressBar bar = new ConsoleProgressBar("测试ConsoleApplication ProgressBar");

                int c = r.Next(534);

                for (int i = 1; i <= c; i++)
                {
                    bar.Update(i, c, string.Format("完成进度:{0}/{1}", i, c));

                    System.Threading.Thread.Sleep(10);
                }
                // 等待退出 
                Console.ReadKey(true);
            }    
        }
    }

 

源码:

 public class ConsoleProgressBar
    {
        int left = 0;
        int backgroundLength = 50;

        #region [ window api ]

        ConsoleColor colorBack = Console.BackgroundColor;
        ConsoleColor colorFore = Console.ForegroundColor;

        private const int STD_OUTPUT_HANDLE = -11;
        private int mHConsoleHandle;
        COORD barCoord;

        [StructLayout(LayoutKind.Sequential)]
        public struct COORD
        {
            public short X;
            public short Y;
            public COORD(short x, short y)
            {
                X = x;
                Y = y;
            }
        }

        [StructLayout(LayoutKind.Sequential)]
        struct SMALL_RECT
        {
            public short Left;
            public short Top;
            public short Right;
            public short Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct CONSOLE_SCREEN_BUFFER_INFO
        {
            public COORD dwSize;
            public COORD dwCursorPosition;
            public int wAttributes;
            public SMALL_RECT srWindow;
            public COORD dwMaximumWindowSize;
        }

        [DllImport("kernel32.dll", EntryPoint = "GetStdHandle", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int GetStdHandle(int nStdHandle);

        [DllImport("kernel32.dll", EntryPoint = "GetConsoleScreenBufferInfo", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int GetConsoleScreenBufferInfo(int hConsoleOutput, out CONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo);

        [DllImport("kernel32.dll", EntryPoint = "SetConsoleCursorPosition", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int SetConsoleCursorPosition(int hConsoleOutput, COORD dwCursorPosition);

        public void SetCursorPos(short x, short y)
        {
            SetConsoleCursorPosition(mHConsoleHandle, new COORD(x, y));
        }

        public COORD GetCursorPos()
        {
            CONSOLE_SCREEN_BUFFER_INFO res;
            GetConsoleScreenBufferInfo(mHConsoleHandle, out res);
            return res.dwCursorPosition;
        }

        #endregion

        public ConsoleProgressBar(string title, int left = 10)
        {
            Console.WriteLine();
            //获取当前窗体句柄
            mHConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
            //获取当前窗体偏移量
            barCoord = this.GetCursorPos();

            this.left = left;
            //获取字符长度
            int len = GetStringLength(title);
            //设置标题的相对居中位置
            Console.SetCursorPosition(left + (backgroundLength / 2 - len), barCoord.Y);
            Console.Write(title);

            //写入进度条背景
            Console.BackgroundColor = ConsoleColor.DarkCyan;
            Console.SetCursorPosition(left, barCoord.Y + 1);

            for (int i = 0; ++i <= backgroundLength; )
                Console.Write(" ");

            Console.WriteLine();
            Console.BackgroundColor = colorBack;
        }
        /// <summary>
        
/// 更新进度条
        
/// </summary>
        
/// <param name="current">当前进度</param>
        
/// <param name="total">总进度</param>
        
/// <param name="message">说明文字</param>
        public void Update(int current, int total, string message)
        {
            //计算百分比
            int i = (int)Math.Ceiling(current / (double)total * 100);

            Console.BackgroundColor = ConsoleColor.Yellow;
            Console.SetCursorPosition(left, barCoord.Y + 1);

            //写入进度条
            StringBuilder bar = new StringBuilder();
            //当前百分比*进度条总长度=要输出的进度最小单位数量
            int count = (int)Math.Ceiling((double)i / 100 * backgroundLength);
            for (int n = 0; n < count; n++) bar.Append(" ");
            Console.Write(bar);
            //设置和写入百分比
            Console.BackgroundColor = colorBack;
            Console.ForegroundColor = ConsoleColor.Green;
            Console.SetCursorPosition(left + backgroundLength, barCoord.Y + 1);
            Console.Write(" {0}% ", i);
            Console.ForegroundColor = colorFore;
            //获取字符长度
            int len = GetStringLength(message);
            //获取相对居中的message偏移量
            Console.SetCursorPosition(left + (backgroundLength / 2 - len), barCoord.Y + 2);
            Console.Write(message);
            //进度完成另起新行作为输出
            if (i >= 100) Console.WriteLine();
        }

        /// <summary>
        
/// 获取字符长度
        
/// </summary>
        
/// <remarks>中文和全角占长度1,英文和半角字符2个字母占长度1</remarks>
        
/// <param name="message"></param>
        
/// <returns></returns>
        private int GetStringLength(string message)
        {
            int len = Encoding.ASCII.GetBytes(message).Count(b => b == 63);
            return (message.Length - len) / 2 + len;
        }
    }

 

posted @ 2012-10-25 15:21  <Nigel>  阅读(2562)  评论(7编辑  收藏  举报