[原创]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);
}
}
}
{
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;
}
}
{
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;
}
}