我看过其他一些与此非常相似的帖子,但他们给出的答案并没有正确回答这个问题。对不起,如果有隐藏的东西我找不到......
我想使用Console.WriteLine()打印当前Console.ReadLine()之上的内容,例如,我的应用程序打印“Hello world”并启动一个线程(在5秒内)将打印“我等待5秒“在我需要输入内容的行上方,如下:
Hello world
Please input something: _
然后5秒钟将会过去,它将如下所示:
Hello world
I just waited 5 seconds
Please input something: _
到目前为止,我已尝试使用Console.SetCursorPosition(0,Console.CursorTop - 1),但这只是打印在“请输入内容:_”这一行,如果我使用Console.CursorTop - 2而不是崩溃说“ [2]超出范围“(不知道为什么会这样)并且如果我使用Console.CursorTop - 2它打印在”请输入内容:_“...所以我的问题是我如何打印上面的内容”请输入一些东西:_“
答案 0 :(得分:5)
只是移动光标不够好,问题是你插入文本。这是可能的,Console.MoveBufferArea()方法允许您访问控制台的底层屏幕缓冲区,并允许您将文本和属性移动到另一行。
有几个棘手的角落案例。你已经找到的,如果光标位于缓冲区的末尾,你必须强制控制台滚动。并且计时器是一个非常难以解决的问题,如果您可以阻止Console.ReadLine()在计时器的Elapsed事件插入文本的同时移动光标,则您只能正确执行此操作。这需要lock
,您无法在Console.ReadLine()中插入锁。
您可以使用一些示例代码来实现目标:
static string TimedReadline(string prompt, int seconds) {
int y = Console.CursorTop;
// Force a scroll if we're at the end of the buffer
if (y == Console.BufferHeight - 1) {
Console.WriteLine();
Console.SetCursorPosition(0, --y);
}
// Setup the timer
using (var tmr = new System.Timers.Timer(1000 * seconds)) {
tmr.AutoReset = false;
tmr.Elapsed += (s, e) => {
if (Console.CursorTop != y) return;
int x = Cursor.Left;
Console.MoveBufferArea(0, y, Console.WindowWidth, 1, 0, y + 1);
Console.SetCursorPosition(0, y);
Console.Write("I just waited {0} seconds", seconds);
Console.SetCursorPosition(x, y + 1);
};
tmr.Enabled = true;
// Write the prompt and obtain the user's input
Console.Write(prompt);
return Console.ReadLine();
}
}
样本用法:
static void Main(string[] args) {
for (int ix = 0; ix < Console.BufferHeight; ++ix) Console.WriteLine("Hello world");
var input = TimedReadline("Please input something: ", 2);
}
注意Console.Top属性上的测试,它确保当用户键入太多文本并强制滚动或者Console.ReadLine()在计时器选中的同时完成时,没有任何事情发生严重错误。在所有可能的情况下证明它是线程安全的很难做到,当Console.ReadLine()在Elapsed事件处理程序运行的同时水平移动光标时肯定会出现问题。我建议你写your own Console.ReadLine() method,这样你就可以插入锁,并确信它总是安全的。
答案 1 :(得分:0)
您可以使用回车符(\r
或U + 000D)将光标返回到当前行的开头,然后覆盖其中的内容。像
// A bunch of spaces to clear the previous output
Console.Write("\r ");
Console.WriteLine("\rI just waited 5 seconds");
Console.Write("Please input something: ");
但是,如果用户已经开始输入,那么这将不再有效(因为您可能无法覆盖他们键入的所有内容,并且他们将丢失他们在屏幕上输入的内容,尽管它仍然在记忆中。
要正确解决此问题,您实际上需要修改控制台的字符缓冲区。您必须将当前行上方的所有内容移动一行,然后插入您的消息。您可以使用Console.MoveBufferArea
向上移动区域。然后你需要保存当前光标位置,将光标移动到上面一行的开头,写下你的信息,然后再次将光标位置重置为保存的光标位置。
然后然后你必须希望用户在你写信的时候没有打字,因为这样会搞砸。我不确定您在使用ReadLine
时是否可以解决这个问题,因为在ReadLine
处于活动状态时您无法暂时锁定某些内容。要正确解决这个问题,您可能必须编写自己的ReadLine
替代方案来读取单个按键,并在写入结果字符时锁定公共对象,以避免两个线程同时写入控制台。