在不断报告进度的Windows控制台应用程序中使用C#4如何使屏幕的“重绘”更加流畅?
我想做以下其中一项: - 让它只“重绘”正在改变的屏幕部分(进度部分),并保持原样。 - “重绘”整个屏幕,但没有闪烁。
目前我重写了所有文本(应用程序名称等)。像这样:
Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));
导致大量闪烁。
答案 0 :(得分:15)
试试Console.SetCursorPosition
。更多详情:How can I update the current line in a C# Windows Console App?
答案 1 :(得分:6)
static void Main(string[] args)
{
Console.SetCursorPosition(0, 0);
Console.Write("################################");
for (int row = 1; row < 10; row++)
{
Console.SetCursorPosition(0, row);
Console.Write("# #");
}
Console.SetCursorPosition(0, 10);
Console.Write("################################");
int data = 1;
System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
clock.Start();
while (true)
{
data++;
Console.SetCursorPosition(1, 2);
Console.Write("Current Value: " + data.ToString());
Console.SetCursorPosition(1, 3);
Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
Thread.Sleep(1000);
}
Console.ReadKey();
}
答案 2 :(得分:5)
我知道这个问题有点陈旧但我发现如果你设置Console.CursorVisible = false
,那么闪烁也会停止。
答案 3 :(得分:0)
答案 4 :(得分:0)
我认为您可以在Windows控制台中使用\ r来返回行的开头。 您也可以使用SetCursorPosition。
答案 5 :(得分:0)
这是一个简单的工作演示,显示多行使用而不会闪烁。它每秒显示当前时间和随机字符串。
private static void StatusUpdate()
{
var whiteSpace = new StringBuilder();
whiteSpace.Append(' ', 10);
var random = new Random();
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
while (true)
{
Console.SetCursorPosition(0, 0);
var sb = new StringBuilder();
sb.AppendLine($"Program Status:{whiteSpace}");
sb.AppendLine("-------------------------------");
sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
sb.AppendLine("-------------------------------");
Console.Write(sb);
Thread.Sleep(1000);
}
}
上面的示例假设您的控制台窗口为空,以便启动。如果没有,请确保首先使用Console.Clear()。
技术说明: SetCursorPosition(0,0)将光标放回到顶部(0,0),因此下一次调用Console.Write将从第0行开始,char 0.注意,它不会在写入之前删除以前的内容。例如,如果你在前一行(如“0123456”)上写“asdf”,那么你最终会在该行上输入类似“asdf456”的内容。因此,我们使用whiteSpace变量来确保前一行中的任何延迟字符都被空格覆盖。调整whiteSpace变量的长度以满足您的需要。对于更改的行,您只需要whiteSpace变量。
个人注意事项 出于我的目的,我想显示应用程序的当前状态(每秒一次)以及一堆其他状态信息,我想避免在使用Console.Clear()时可能发生的任何烦人的闪烁。在我的应用程序中,我在一个单独的线程后面运行我的状态更新,因此它会不断提供更新,即使我有许多其他线程和长时间运行的任务同时进行。
<强>现金:强> 感谢以前的海报和dtb,用于演示中使用的随机字符串生成器。 How can I generate random alphanumeric strings in C#?
答案 6 :(得分:0)
我建议以下扩展方法。它们使您可以使用StringBuilder刷新控制台视图而没有任何闪烁,并且还可以整理每行上的所有残留字符
问题:以下演示演示了如何使用标准的StringBuilder,其中比以前编写的行短的更新行变得混乱。它是通过先写一个短字符串,然后在循环上写一个长字符串来实现的:
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLine("Short msg");
else
sb.AppendLine("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
结果:
解决方案:通过使用下面提供的扩展方法,问题得以解决
public static void Main(string[] args)
{
var switchTextLength = false;
while(true)
{
var sb = new StringBuilder();
if (switchTextLength)
sb.AppendLineEx("Short msg");
else
sb.AppendLineEx("Longer message");
sb.UpdateConsole();
switchTextLength = !switchTextLength;
Thread.Sleep(500);
}
}
结果:
扩展方法:
public static class StringBuilderExtensions
{
/// <summary>
/// Allows StrinbBuilder callers to append a line and blank out the remaining characters for the length of the console buffer width
/// </summary>
public static void AppendLineEx(this StringBuilder c, string msg)
{
// Append the actual line
c.Append(msg);
// Add blanking chars for the rest of the buffer
c.Append(' ', Console.BufferWidth - msg.Length - 1);
// Finish the line
c.Append(Environment.NewLine);
}
/// <summary>
/// Combines two StringBuilders using AppendLineEx
/// </summary>
public static void AppendEx(this StringBuilder c, StringBuilder toAdd)
{
foreach (var line in toAdd.ReadLines())
{
c.AppendLineEx(line);
}
}
/// <summary>
/// Hides the console cursor, resets its position and writes out the string builder
/// </summary>
public static void UpdateConsole(this StringBuilder c)
{
// Ensure the cursor is hidden
if (Console.CursorVisible) Console.CursorVisible = false;
// Reset the cursor position to the top of the console and write out the string builder
Console.SetCursorPosition(0, 0);
Console.WriteLine(c);
}
}
答案 7 :(得分:0)
我实际上遇到了这个问题,所以我做了一个快速简单的方法来尝试消除这个问题。
static void Clear(string text, int x, int y)
{
char[] textChars = text.ToCharArray();
string newText = "";
//Converts the string you just wrote into a blank string
foreach(char c in textChars)
{
text = text.Replace(c, ' ');
}
newText = text;
//Sets the cursor position
Console.SetCursorPosition(x, y);
//Writes the blank string over the old string
Console.WriteLine(newText);
//Resets cursor position
Console.SetCursorPosition(0, 0);
}
实际上效果很好,我希望它可能对您有用!