您可以通过将Out或Error属性的TextWriter.NewLine属性设置为另一个行终止字符串来解决此问题 . 例如,C#语句Console.Error.NewLine =“\ r \ n \ r \ n”;;将标准错误输出流的行终止字符串设置为两个回车符和换行符序列 . 然后,您可以显式调用错误输出流对象的WriteLine方法,如在C#语句中,Console.Error.WriteLine();
int sleepTime = 5 * 60; // 5 minutes
for (int secondsRemaining = sleepTime; secondsRemaining > 0; secondsRemaining --)
{
double minutesPrecise = secondsRemaining / 60;
double minutesRounded = Math.Round(minutesPrecise, 0);
int seconds = Convert.ToInt32((minutesRounded * 60) - secondsRemaining);
Console.Write($"\rProcess will resume in {minutesRounded}:{String.Format("{0:D2}", -seconds)} ");
Thread.Sleep(1000);
}
Console.WriteLine("");
12
\r 用于此方案 . \rrepresents a carriage return which means the cursor returns to the start of the line. 这就是为什么Windows使用 \n\r 作为它的新行标记 . \n 向下移动一行, \r 返回到行的开头 .
0
SetCursorPosition 方法适用于多线程场景,而其他两种方法则不适用
224
我在vb.net中寻找相同的解决方案,我找到了这个,这很棒 .
然而,正如@JohnOdom建议一个更好的方法来处理空白空间,如果前一个空间大于当前空间 .
我在vb.net中创建了一个函数,并认为有人可以得到帮助..
这是我的代码:
Private Sub sPrintStatus(strTextToPrint As String, Optional boolIsNewLine As Boolean = False)
REM intLastLength is declared as public variable on global scope like below
REM intLastLength As Integer
If boolIsNewLine = True Then
intLastLength = 0
End If
If intLastLength > strTextToPrint.Length Then
Console.Write(Convert.ToChar(13) & strTextToPrint.PadRight(strTextToPrint.Length + (intLastLength - strTextToPrint.Length), Convert.ToChar(" ")))
Else
Console.Write(Convert.ToChar(13) & strTextToPrint)
End If
intLastLength = strTextToPrint.Length
End Sub
public class DumpOutPutInforInSameLine
{
//content show in how many lines
int TotalLine = 0;
//start cursor line
int cursorTop = 0;
// use to set character number show in one line
int OneLineCharNum = 75;
public void DumpInformation(string content)
{
OutPutInSameLine(content);
SetBackSpace();
}
static void backspace(int n)
{
for (var i = 0; i < n; ++i)
Console.Write("\b \b");
}
public void SetBackSpace()
{
if (TotalLine == 0)
{
backspace(OneLineCharNum);
}
else
{
TotalLine--;
while (TotalLine >= 0)
{
backspace(OneLineCharNum);
TotalLine--;
if (TotalLine >= 0)
{
Console.SetCursorPosition(OneLineCharNum, cursorTop + TotalLine);
}
}
}
}
private void OutPutInSameLine(string content)
{
//Console.WriteLine(TotalNum);
cursorTop = Console.CursorTop;
TotalLine = content.Length / OneLineCharNum;
if (content.Length % OneLineCharNum > 0)
{
TotalLine++;
}
if (TotalLine == 0)
{
Console.Write("{0}", content);
return;
}
int i = 0;
while (i < TotalLine)
{
int cNum = i * OneLineCharNum;
if (i < TotalLine - 1)
{
Console.WriteLine("{0}", content.Substring(cNum, OneLineCharNum));
}
else
{
Console.Write("{0}", content.Substring(cNum, content.Length - cNum));
}
i++;
}
}
}
class Program
{
static void Main(string[] args)
{
DumpOutPutInforInSameLine outPutInSameLine = new DumpOutPutInforInSameLine();
outPutInSameLine.DumpInformation("");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
//need several lines
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
outPutInSameLine.DumpInformation("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
outPutInSameLine.DumpInformation("bbbbbbbbbbbbbbbbbbbbbbbbbbb");
}
}
public class ConsoleSpiner : IDisposable
{
private static readonly string INDICATOR = "/-\\|";
private static readonly string MASK = "\r{0} {1:c} {2}";
int counter;
Timer timer;
string message;
public ConsoleSpiner() {
counter = 0;
timer = new Timer(200);
timer.Elapsed += TimerTick;
}
public void Start() {
timer.Start();
}
public void Stop() {
timer.Stop();
counter = 0;
}
public string Message {
get { return message; }
set { message = value; }
}
private void TimerTick(object sender, ElapsedEventArgs e) {
Turn();
}
private void Turn() {
counter++;
var elapsed = TimeSpan.FromMilliseconds(counter * 200);
Console.Write(MASK, INDICATOR[counter % 4], elapsed, this.Message);
}
public void Dispose() {
Stop();
timer.Elapsed -= TimerTick;
this.timer.Dispose();
}
}
用法是这样的 . 课程{
static void Main(string[] args) {
using (var spinner = new ConsoleSpiner()) {
spinner.Start();
spinner.Message = "About to do some heavy staff :-)"
DoWork();
spinner.Message = "Now processing other staff".
OtherWork();
spinner.Stop();
}
Console.WriteLine("COMPLETED!!!!!\nPress any key to exit.");
}
0
这是另一个:D
class Program
{
static void Main(string[] args)
{
Console.Write("Working... ");
int spinIndex = 0;
while (true)
{
// obfuscate FTW! Let's hope overflow is disabled or testers are impatient
Console.Write("\b" + @"/-\|"[(spinIndex++) & 3]);
}
}
}
15 回答
在行的开头明确地使用Carrage Return(\ r)而不是(隐式或显式地)在末尾使用新行(\ n)应该得到你想要的 . 例如:
如果仅将
"\r"
打印到控制台,则光标会返回到当前行的开头,然后您可以重写它 . 这应该是诀窍:注意数字后面的几个空格,以确保删除之前的任何内容 .
另请注意使用
Write()
而不是WriteLine()
,因为您不想在行尾添加"\n" .从MSDN中的控制台文档:
所以 - 我这样做了:
然后我就能自己控制输出;
到达那里的另一种方式 .
我正在搜索这个,看看我写的解决方案是否可以针对速度进行优化 . 我想要的是倒计时器,而不仅仅是更新当前线路 . 这就是我想出的 . 可能对某人有用
\r
用于此方案 .\r
represents a carriage return which means the cursor returns to the start of the line.这就是为什么Windows使用
\n\r
作为它的新行标记 .\n
向下移动一行,\r
返回到行的开头 .SetCursorPosition
方法适用于多线程场景,而其他两种方法则不适用我在vb.net中寻找相同的解决方案,我找到了这个,这很棒 .
然而,正如@JohnOdom建议一个更好的方法来处理空白空间,如果前一个空间大于当前空间 .
我在vb.net中创建了一个函数,并认为有人可以得到帮助..
这是我的代码:
我只需要玩divo的
ConsoleSpinner
课程 . 我的目标并不简洁,但是我觉得这个类的用户必须编写自己的while(true)
循环 . 我正在拍摄更像这样的体验:我用下面的代码意识到了这一点 . 由于我不希望我的
Start()
方法被阻止,我不希望用户不必担心编写类似while(spinFlag)
的循环,并且我想允许多个微调器同时我必须生成一个单独的线程处理纺纱 . 这意味着代码必须要复杂得多 .此外,我没有做那么多的多线程,所以我可能(甚至可能)我在那里留下了一个微妙的错误或三个 . 但到目前为止似乎工作得很好:
如果您想要更新一行,但信息太长而无法在一行显示,则可能需要一些新行 . 我遇到过这个问题,下面是解决这个问题的一种方法 .
您可以使用 \b (退格)转义序列来备份当前行上的特定数量的字符 . 这只是移动当前位置,它不会删除字符 .
例如:
这里, line 是写入控制台的百分比行 . 诀窍是为前一个输出生成正确数量的 \b 字符 .
相对于 \r 方法,这样做的好处是即使您的百分比输出不在行的开头也能正常工作 .
您可以使用
Console.SetCursorPosition
设置光标的位置,然后在当前位置写入 .这是example显示一个简单的"spinner":
请注意,您必须确保使用新输出或空白覆盖任何现有输出 .
更新:由于有人批评该示例仅将光标移回一个字符,我将添加此内容以澄清:使用
SetCursorPosition
您可以将光标设置为控制台窗口中的任何位置 .将光标设置为当前行的开头(或者您可以直接使用
Console.CursorLeft = 0
) .这是我对s soosh和0xA3的回答 . 它可以在更新微调器的同时用用户消息更新控制台,并且还有一个经过时间指示器 .
用法是这样的 . 课程{
这是另一个:D
到目前为止,我们有三个竞争对手如何做到这一点的替代方案:
我总是使用
Console.CursorLeft = 0
,第三种选择的变种,所以我决定做一些测试 . 这是我使用的代码:在我的机器上,我得到以下结果:
退格: 25.0 seconds
回车: 28.7 seconds
SetCursorPosition: 49.7 seconds
此外,
SetCursorPosition
引起了明显的闪烁,我没有观察到任何一种替代方案 . 所以,道德是 use backspaces or carriage returns when possible ,而 thanks for teaching me 这是一个更快的方法,所以!Update :在评论中,Joel建议SetCursorPosition相对于移动的距离是恒定的,而其他方法是线性的 . 进一步的测试证实了这种情况, however 恒定时间和慢速仍然很慢 . 在我的测试中,将一长串退格写入控制台比SetCursorPosition更快,直到大约60个字符 . 因此,退格会更快地替换短于60个字符(或左右)的部分行, and 它不会支持我最初代表\ b over \ r和
SetCursorPosition
.