2017-02-08 4 views
5

Я видел несколько других сообщений, очень похожих на этот, но ответы, которые они дают, неверно отвечают на вопрос. Извините, если есть что-то скрытое, что я не смог найти ...Консольное приложение - WriteLine над текущей рабочей линией

Я хочу использовать 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.Cur sorTop - 1), но это просто печатает по строке «Пожалуйста, введите что-то: _», и если я использую Console.CursorTop - 2, вместо этого он выйдет из строя, сказав «[2] Вне диапазона» (не знаю, почему это так), и если я использую Console.CursorTop - 2 он печатает в разделе «Пожалуйста, введите что-то: _» ... так что мой вопрос: как напечатать что-то ВЫШЕУ строку «Пожалуйста, введите что-то: _»

+1

Я даже не думаю, что это возможно, не так ли? Консоль - это «когда-то написанный, это есть» тип сделки, нет? – jleach

+1

@ jdl134679 Я видел, как программа делает это до –

+1

@ jdl134679: Стандартный выходной поток да, но вы можете изменить буфер символа консоли, если хотите. – Joey

ответ

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 для перемещения область вверх. Затем вам нужно сохранить текущую позицию курсора, переместить курсор в начало строки выше, записать сообщение и сбросить курсор p снова к спасенному.

И , то, вы должны надеяться, что пользователь не набирает, пока вы пишете свое сообщение, потому что это испортит ситуацию. Я не уверен, что вы можете решить это при использовании ReadLine, хотя, поскольку вы не можете временно заблокировать что-то, пока активен ReadLine. Чтобы правильно решить это, вам, возможно, придется написать свой собственный вариант ReadLine, который читает отдельные нажатия клавиш и будет блокировать общий объект при записи результирующего символа, чтобы избежать одновременного записи двух потоков на консоль.

+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, чтобы вы могли вставить замок и чувствовать себя уверенно, что он всегда безопасен.