2012-05-29 11 views
18

chciałbym osiągnąć coś takiego:Jak zmodyfikować poprzedni wiersz tekstu konsoli?

Time consuming operation...OK 
Another time consuming operation... 
And another one, but it completed, so...OK 

ja wyświetlona 3 linii tekstu, każdy związany z wątku, który może prędzej czy później. Ale jeśli drugi kompletny później niż trzeci, otrzymam coś takiego:

Co jest oczywiście niedopuszczalne. Wiem, jak wrócić do obecnej linii, ale czy istnieje sposób, aby przejść w górę? Przysiągłbym, że go gdzieś widziałem, ale może to być konsola Linuksa :)

Zapomnij o tym. Zobacz Far File Manager! Działa na konsoli Windows, działa nawet w PowerShell! Jak zrobić coś takiego? A najfajniejszą częścią jest przywrócenie stanu konsoli po wyjściu. Więc może powinienem zapytać - jak uzyskać bezpośredni dostęp do bufora konsoli? Zakładam, że potrzebuję jakiegoś kodu natywnego, aby zrobić lewę, ale może jest inny sposób? Myślałem o czyszczeniu konsoli przy każdej aktualizacji, ale wydaje się to przesadą. A może nie jest? Czy to zamigocze?

+0

byłby już miło, gdyby trzeba było wliczone jak „cofnąć się w bieżącej linii”, a nie po prostu stwierdzić, że o tym wiesz. Oto, jak to zrobiłem: 'Console.SetCursorPosition (0, Console.CursorTop);' Wiem, że to nie jest bezpośrednio część pytania, ale jest powiązane, i to jest pytanie, które znalazłem, kiedy go szukałem. –

Odpowiedz

48

Możesz przesuwać kursor, gdzie chcesz: Console.SetCursorPosition lub użyć Console.CursorTop.

Console.SetCursorPosition(0, Console.CursorTop -1); 
Console.WriteLine("Over previous line!!!"); 
+1

Tak. To jest to. Teraz robię klasy, aby dodać kontenery, takie jak DIV w HTML, do tekstu konsoli. Zapamiętuje położenie każdego pojemnika, dzięki czemu można go później zmienić. Teraz mogę w końcu dokończyć mój serwer :) Cóż, to wciąż wstawka, ale tam Console.MoveBufferArea będzie przydatna. Dzięki. – Harry

4

Użyj powrotu karetki. Ta próbka drukuje pojedynczą linię, zastępując to, co było wcześniej.

Console.WriteLine(); 
    for (int i = 0; i <= 100; i++) 
    { 
    System.Threading.Thread.Sleep(10); 
    Console.Write("\x000DProgress: " + i); 
    } 

Działa to tak długo, jak wszystkie ciągi są mniej niż 80 kolumn (lub bez względu na bufor terminal jest ustawiony).

+1

Zakładam, że działa to tylko w systemie Windows, ale nie próbowałem go na mono. –

+1

Działa dobrze, ale nie można go użyć do zmiany linii. Jest to jednak prosty sposób na zrobienie pojedynczego paska postępu lub aktualizację procentową. – Harry

+1

'\ r' działa również zamiast' \ x000D'. – jnm2

1

Uwaga: Poniższa odpowiedź została pierwotnie zredagowana na pytanie przez PO.


Oto kompletne rozwiązanie z Demo:

using System; 
using System.Collections.Generic; 
using System.Threading; 

namespace PowerConsole { 

    internal class Containers { 

     internal struct Container { 
      public int Id; 
      public int X; 
      public int Y; 
      public string Content; 
     } 

     public static List<Container> Items = new List<Container>(); 

     private static int Identity = 0; 

     public static int Add(string text) { 
      var c = new Container(); 
      c.Id = Identity++; 
      c.X = Console.CursorLeft; 
      c.Y = Console.CursorTop; 
      c.Content = text; 
      Console.Write(text); 
      Items.Add(c); 
      return c.Id; 
     } 

     public static void Remove(int id) { 
      Items.RemoveAt(id); 
     } 

     public static void Replace(int id, string text) { 
      int x = Console.CursorLeft, y = Console.CursorTop; 
      Container c = Items[id]; 
      Console.MoveBufferArea(
       c.X + c.Content.Length, c.Y, 
       Console.BufferWidth - c.X - text.Length, 1, 
       c.X + text.Length, c.Y 
      ); 
      Console.CursorLeft = c.X; 
      Console.CursorTop = c.Y; 
      Console.Write(text); 
      c.Content = text; 
      Console.CursorLeft = x; 
      Console.CursorTop = y; 
     } 

     public static void Clear() { 
      Items.Clear(); 
      Identity = 0; 
     } 
    } 

    internal class Program { 
     private static List<Thread> Threads = new List<Thread>(); 

     private static void Main(string[] args) { 
      Console.WriteLine("So we have some threads:\r\n"); 
      int i, id; 
      Random r = new Random(); 
      for (i = 0; i < 10; i++) { 
       Console.Write("Starting thread " + i + "...["); 
       id = Containers.Add("?"); 
       Console.WriteLine("]"); 
       Thread t = new Thread((object data) => { 
        Thread.Sleep(r.Next(5000) + 100); 
        Console.ForegroundColor = ConsoleColor.Green; 
        Containers.Replace((int)data, "DONE"); 
        Console.ResetColor(); 
       }); 
       Threads.Add(t); 
      } 
      Console.WriteLine("\n\"But will it blend?\"..."); 
      Console.ReadKey(true); 
      i = 0; 
      Threads.ForEach(t => t.Start(i++)); 
      Threads.ForEach(t => t.Join()); 
      Console.WriteLine("\r\nVoila."); 
      Console.ReadKey(true); 
     } 
    } 
} 
+1

Działa lekker, wystarczy dodać jeszcze jeden wiersz na końcu w metodzie "Replace". Items [id] = c; '. To rozwiąże problem ciągłego zastępowania, w którym postacie zaczynają się toczyć z błędnymi wartościami. – Pierre

+1

@Pierre Dzięki za komentarz! Nie zweryfikowałem kodu poprawności, więc możliwe, że występują w nim pewne problemy. – Stijn

Powiązane problemy