2017-02-08 8 views
5

私はこれに非常によく似たいくつかの投稿を見ましたが、それらの回答は質問に正しく答えていません。私が現在のConsole.ReadLine()の上に何かを印刷するためにConsole.WriteLine()を使用したいと思います。例えば、私のアプリケーションは "Hello world"を出力します。コンソールアプリケーション - 現在の作業ラインの上にあるWriteLine

Hello world 
Please input something: _ 

その後5秒が合格すると、それは次のようになります。私は入力に、このようなものを、必要な線の上に「私はわずか5秒を待っていた」出力します(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それは下に印刷さ「を入力してください何か:_」...ので、私の質問はどのように私は線の上に何かを印刷する「を入力してください何か:_」やる\r

+1

私はこれが可能だとは思わないでしょうか?コンソールは「一度書かれた、そこにある」タイプの取引である、いいえ? – jleach

+1

@ jdl134679これまでにプログラムを見たことがあります –

+1

@ jdl134679:標準出力ストリームはありますが、必要に応じてコンソールの文字バッファを変更できます。 – Joey

答えて

0

あなたは、キャリッジリターンを使用することができますが、または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: "); 

ような何かユーザーが既に入力を開始している場合は、彼らが入力したすべてを上書きしないこと、そして彼らが画面上を入力したものを失うことになるしかし、これは、(もう機能しません

これを適切に解決するには、実際にコンソールの文字バッファを変更する必要があります。現在の行の上にあるすべての行を1行上に移動し、メッセージを挿入する必要があります。Console.MoveBufferAreaを使用して移動できます。領域を上に移動し、現在のカーソル位置を保存し、上の行の先頭にカーソルを移動し、メッセージを書き、カーソルpをリセットする必要があります保存されたものにもう一度行きます。

次にあなたはメッセージを書いている間にユーザーが入力しないことを願ってください。 ReadLineがアクティブな間に一時的に何かをロックできないので、私はあなたがそれを解決することができると確信していません。ReadLine。これを適切に解決するには、個々のキー押下を読み取って結果の文字を書き込む際に共通のオブジェクトをロックし、同時に2つのスレッドがコンソールに書き込まれるのを避ける独自の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と書くことをお勧めします。ロックを挿入して、常に安全であると自信を持って感じることができます。

関連する問題