2009-12-17 2 views
31

Я просто хочу знать, как создавать простые анимации, такие как мигание, перемещение материалов на консольных приложениях C#. Есть ли специальный метод для этого?Консольные анимации

+0

+1 Loved this question, IMMD =) –

ответ

3

Вы должны будете использовать Console.ForegroundColor, Console.BackgroundColor и Console.SetCursorPosition(int, int)

EDIT: Для вдохновения, Let's Dance

+1

Мне очень хотелось бы увидеть кадры анимации Lets Dance как текст, поэтому мы можем реализовать такую ​​анимацию, как консоль Spinner. – TaterJuice

5

Да, есть quite a few methods для этого.

В частности, вы можете захотеть взглянуть на следующие методы консоли:

  1. SetCursorPosition (вы можете перемещать курсор, и замены элементов)
  2. MoveBufferArea (копировать/вставить поверх областей)
  3. ForegroundColor и BackgroundColor (изменение окраски)
0

я не слишком уверен, что я точно знаю, что вы на о. но я дам ему шанс. Я думаю, что самый большой и лучший способ вызвать «мигающий» аффект (или то, что я считаю мигающим аффектом) - использовать возврат каретки. Лучший способ объяснить это вам - показать вам эксперимент Foo Bar. запустите новый проект, и в своей основной функции попробуйте это.

Console.WriteLine("Foo/nBar"); 

Результат будет выглядеть как этот

Foo 
Bar 

Но если вы используете возврат каретки.

Console.WriteLine("Foo/rBar"); 

Результат будет выглядеть как этот

Bar 

Причина в том, что Foo написано, то возврат каретки Возврат в начало строки, а затем Bar написано. Все, что вы когда-либо видели, это Бар. Это может быть полезно для «Перемещение» вещей на одной линии, вместо того, чтобы переписывать одни и те же вещи снова на нескольких строках. Простой способ использовать Console.Write(); Попробуйте это.

Console.Write("Loading"); 
for(int i = 0; i < 10; i++) 
{ 
    Thread.Sleep(1000); 
    Console.Write("."); 
} 

Вывод должен быть

Loading 

Вслед за Fullstop каждую секунду в течение 10 секунд.

Если вы комбинируете возврат каретки с Console.Write(); вы можете писать несколько вещей в одной строке, очищать строку и писать что-то еще, или, действительно, одно и то же просто немного перемещено. (Это, конечно, нужно больше, чем я показал вам, например, запись, в которой находится «объект», который вы контролируете. Если вам нужен короткий пример, я был бы рад сделать это, просто прокомментировать и спросить меня об этом :)

Редактировать: Я заметил людей, говорящих о цвете, который я забыл. Если вы делали анимацию, я предполагаю, что цвет будет обязательным. ForegroundColor и BackgroundColor находятся там, где он находится. обратите внимание, что ForegroundColor применит к следующим символам, записанным на консоль, и не будет полностью перекрашивать консоль. /Edit

Я надеюсь, что это помогает,

Skintkingle;)

+0

Это, к сожалению, не работает в большинстве случаев. Вы не можете перейти к строке с \ r, поэтому вы очень ограничены, не используя Console.SetCursorPosition –

+0

Ах да, конечно. Я больше не играю в Консоли, я забываю самые очевидные вещи. :) – Skintkingle

41

Традиционной консоль Spinner:

static void Main(string[] args) 
    { 
     ConsoleSpiner spin = new ConsoleSpiner(); 
     Console.Write("Working...."); 
     while (true) 
     { 
      spin.Turn(); 
     } 
    } 

public class ConsoleSpiner 
{ 
    int counter; 
    public ConsoleSpiner() 
    { 
     counter = 0; 
    } 
    public void Turn() 
    { 
     counter++;   
     switch (counter % 4) 
     { 
      case 0: Console.Write("/"); break; 
      case 1: Console.Write("-"); break; 
      case 2: Console.Write("\\"); break; 
      case 3: Console.Write("|"); break; 
     } 
     Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); 
    } 
} 
4

Просто увидел это и несколько других нитей об этом и любит этот вид материала ! Я взял хороший кусок кода Tuukka и немного улучшил его, поэтому класс можно легко настроить примерно на любую последовательность вращения. Я, вероятно, добавлю некоторые аксессоры и перегруженный конструктор, чтобы отполировать его и поместить в панель инструментов ol. Забавные вещи!

class ConsoleSpinner 
{ 
    int counter; 
    string[] sequence; 

    public ConsoleSpinner() 
    { 
     counter = 0; 
     sequence = new string[] { "/", "-", "\\", "|" }; 
     sequence = new string[] { ".", "o", "0", "o"}; 
     sequence = new string[] { "+", "x" }; 
     sequence = new string[] { "V", "<", "^", ">" }; 
     sequence = new string[] { ". ", ".. ", "... ", "...." }; 
    } 

    public void Turn() 
    { 
     counter++; 

     if (counter >= sequence.Length) 
      counter = 0; 

     Console.Write(sequence[counter]); 
     Console.SetCursorPosition(Console.CursorLeft - sequence[counter].Length, Console.CursorTop); 
    } 
} 
1

Я думал, что буду перекликать с моей версией ранее указанного кода. Здесь:

class ConsoleSpinner 
{ 
    bool increment = true, 
     loop = false; 
    int counter = 0; 
    int delay; 
    string[] sequence; 

    public ConsoleSpinner(string sSequence = "dots", int iDelay = 100, bool bLoop = false) 
    { 
     delay = iDelay; 
     if (sSequence == "dots") 
     { 
      sequence = new string[] { ". ", ".. ", "... ", "...." }; 
      loop = true; 
     } 
     else if (sSequence == "slashes") 
      sequence = new string[] { "/", "-", "\\", "|" }; 
     else if (sSequence == "circles") 
      sequence = new string[] { ".", "o", "0", "o" }; 
     else if (sSequence == "crosses") 
      sequence = new string[] { "+", "x" }; 
     else if (sSequence == "arrows") 
      sequence = new string[] { "V", "<", "^", ">" }; 
    } 

    public void Turn() 
    { 
     if (loop) 
     { 
      if (counter >= sequence.Length - 1) 
       increment = false; 
      if (counter <= 0) 
       increment = true; 

      if (increment) 
       counter++; 
      else if (!increment) 
       counter--; 
     } 
     else 
     { 
      counter++; 

      if (counter >= sequence.Length) 
       counter = 0; 
     } 

     Console.Write(sequence[counter]); 
     Console.SetCursorPosition(Console.CursorLeft - sequence[counter].Length, Console.CursorTop); 

     System.Threading.Thread.Sleep(delay); 
    } 
} 

задержка добавляет (к сожалению, через Thread.Sleep(), но, эй), способность цикла анимации вперед и назад (начинает обратное, когда она попадает конец), и общие улучшения в целом. Наслаждайтесь!

1

Это будет мой Предпочтительнее метод:

public sealed class Spinner 
{ 
    private static Lazy<Spinner> lazy = 
     new Lazy<Spinner>(()=> new Spinner()); 

    public static void Reset() 
    { 
     lazy = new Lazy<Spinner>(()=> new Spinner()); 
    } 

    public static Spinner Instance { get { return lazy.Value; }} 

    private readonly int _consoleX; 
    private readonly int _consoleY; 
    private readonly char[] _frames = { '|', '/', '-', '\\' }; 
    private int _current; 

    private Spinner() 
    { 
     _current = 0; 
     _consoleX = Console.CursorLeft; 
     _consoleY = Console.CursorTop; 
    } 

    public void Update() 
    { 
     Console.Write(_frames[_current]); 
     Console.SetCursorPosition(_consoleX, _consoleY); 

     if (++_current >= _frames.Length) 
      _current = 0; 
    } 
} 

Вызов Spinner.Instance.Update() начать вертушку в текущей позиции консоли. Любой последовательный вызов будет отображать следующий кадр в том же положении.

Звоните Spinner.Reset(), если вы хотите написать больше текста, а затем добавить новый счетчик в новое место.

8

Вот мой счетчик. Целью этого является, чтобы программа делать какую-то работу в то время как Горячо показывает пользователю, что что-то на самом деле происходит:

public class Spinner : IDisposable 
    { 
    private const string Sequence = @"/-\|"; 
    private int counter = 0; 
    private readonly int left; 
    private readonly int top; 
    private readonly int delay; 
    private bool active; 
    private readonly Thread thread; 

    public Spinner(int left, int top, int delay = 100) 
    { 
     this.left = left; 
     this.top = top; 
     this.delay = delay; 
     thread = new Thread(Spin); 
    } 

    public void Start() 
    { 
     active = true; 
     if (!thread.IsAlive) 
      thread.Start(); 
    } 

    public void Stop() 
    { 
     active = false; 
     Draw(' '); 
    } 

    private void Spin() 
    { 
     while (active) 
     { 
      Turn(); 
      Thread.Sleep(delay); 
     } 
    } 

    private void Draw(char c) 
    { 
     Console.SetCursorPosition(left, top); 
     Console.ForegroundColor = ConsoleColor.Green; 
     Console.Write(c); 
    } 

    private void Turn() 
    { 
     Draw(Sequence[++counter % Sequence.Length]); 
    } 

    public void Dispose() 
    { 
     Stop(); 
    } 
    } 

И вы используете класс как это:

 var spinner = new Spinner(10, 10); 

    spinner.Start(); 

    // Do your work here instead of sleeping... 
    Thread.Sleep(10000); 

    spinner.Stop(); 
+0

Удивительный пример, именно то, что я хотел: в то время как я занимаюсь интенсивной задачей, мне нужен прогрессивный – jjay225

+0

. Пожалуйста, взгляните на мой андерсер, я взял ваш код и немного изменил его. – Rumplin

1

Отличная работа с ConsoleSpinner и реализации последовательности. Спасибо за код. Я подумал о том, чтобы поделиться своим индивидуальным подходом.

public class ConsoleSpinner 
{ 
    static string[,] sequence = null; 

    public int Delay { get; set; } = 200; 

    int totalSequences = 0; 
    int counter; 

    public ConsoleSpinner() 
    { 
     counter = 0; 
     sequence = new string[,] { 
      { "/", "-", "\\", "|" }, 
      { ".", "o", "0", "o" }, 
      { "+", "x","+","x" }, 
      { "V", "<", "^", ">" }, 
      { ". ", ".. ", "... ", "...." }, 
      { "=> ", "==> ", "===> ", "====>" }, 
      // ADD YOUR OWN CREATIVE SEQUENCE HERE IF YOU LIKE 
     }; 

     totalSequences = sequence.GetLength(0); 
    } 

    /// <summary> 
    /// 
    /// </summary> 
    /// <param name="sequenceCode"> 0 | 1 | 2 |3 | 4 | 5 </param> 
    public void Turn(string displayMsg = "", int sequenceCode = 0) 
    { 
     counter++; 

     Thread.Sleep(Delay); 

     sequenceCode = sequenceCode > totalSequences - 1 ? 0 : sequenceCode; 

     int counterValue = counter % 4; 

     string fullMessage = displayMsg + sequence[sequenceCode, counterValue]; 
     int msglength = fullMessage.Length; 

     Console.Write(fullMessage); 

     Console.SetCursorPosition(Console.CursorLeft - msglength, Console.CursorTop); 
    } 
} 

Реализация:

ConsoleSpinner spinner = new ConsoleSpinner(); 
spinner.Delay = 300; 
while (true) 
{ 
    spinner.Turn(displayMsg: "Loading ",sequenceCode:5); 
} 

Выход:

enter image description here

0

Я взял anwser от @ThisGuy и модифицировал его немного, но я заметил, что иногда строка не очищается, как следует.

static void Main(string[] args) 
    { 
     Console.WriteLine("1"); 
     var tddf = XConsole.BusyIndicator("test 0 trtg fdfdfvdgd 4343",() => 
     { 
      return ""; 
     }); 
     Console.WriteLine("2"); 
     var tdd = XConsole.BusyIndicator("test 0 trtg fdfdfvdgd",() => 
     { 
      Thread.Sleep(1); 
      return ""; 
     }); 
     Console.WriteLine("3"); 
     var t = XConsole.BusyIndicator("test 1 trtg vdgd",() => 
     { 
      Thread.Sleep(1000); 
      return ""; 
     }); 
     Console.WriteLine("4"); 
     var xt = XConsole.BusyIndicator("test 2",() => 
     { 
      Thread.Sleep(2000); 
      return ""; 
     }); 
     var xtx = XConsole.BusyIndicator("test 2 csds fsd fdsf ds s",() => 
     { 
      Thread.Sleep(2000); 
      return ""; 
     }); 

     Console.WriteLine("5"); 
     Thread.Sleep(4000); 
    } 

Spinner класс:

public class Spinner : IDisposable 
    { 
     private const string Sequence1 = @"/-\|"; 
     private const string Sequence3 = @".o0o"; 
     private const string Sequence2 = @"<^>v"; 
     private const string Sequence4 = @"#■."; 
     private const string Sequence5 = @"▄▀"; 
     private const string Sequence = @"└┘┐┌"; 
     private string BusyMessage = ""; 
     private int counter = 0; 
     private readonly int delay; 
     private bool active; 
     private readonly Thread thread; 

     public Spinner(int delay = 200) 
     { 
      this.delay = delay; 
      thread = new Thread(Spin); 
     } 

     public void Start() 
     { 
      active = true; 
      Console.CursorVisible = false; 
      if (!thread.IsAlive) 
      { 
       thread.Start(); 
      } 
     } 

     public void Start(string busyMessage) 
     { 
      BusyMessage = busyMessage; 
      Start(); 
     } 

     public void Stop() 
     {   
      active = false; 
      Console.CursorVisible = true; 
      ClearCurrentConsoleLine(); 
      BusyMessage = ""; 
     } 

private static void ClearCurrentConsoleLine() 
{ 
    int currentLineCursor = Console.CursorTop; 
    Console.SetCursorPosition(0, Console.CursorTop); 
    Console.Write(new string(' ', Console.WindowWidth)); 
    Console.SetCursorPosition(0, currentLineCursor); 
} 

     private void Spin() 
     { 
      while (active) 
      { 
       Turn(); 
       Thread.Sleep(delay); 
      } 
     } 

     /// <summary> 
     /// Draws the busy indicator 
     /// </summary> 
     /// <param name="c">if empty char, then clear screen</param> 
    private void Draw(char c) 
    { 
     int left = Console.CursorLeft; 
     int top = Console.CursorTop; 

     Console.Write('['); 
     Console.ForegroundColor = ConsoleColor.Green; 
     Console.Write(c); 
     Console.ForegroundColor = ConsoleColor.Gray; 
     Console.Write(']'); 
     if (!string.IsNullOrEmpty(BusyMessage)) 
     { 
      Console.Write(" " + BusyMessage); 
     } 

     //reset cursor position 
     Console.SetCursorPosition(left, top); 
    } 

     private void Turn() 
     { 
      Draw(Sequence[++counter % Sequence.Length]); 
     } 

     public void Dispose() 
     { 
      Stop(); 
     } 
    } 

Моя консоль Класс:

public static class XConsole { 
    public static T BusyIndicator<T>(Func<T> action) 
    { 
     T result; 

     using (var spinner = new Spinner()) 
     { 
      spinner.Start(); 

      result = action(); 

      spinner.Stop(); 
     } 

     return result; 
    } 

    public static T BusyIndicator<T>(string content, Func<T> action) 
    { 
     T result; 

     using (var spinner = new Spinner()) 
     { 
      spinner.Start(content); 

      result = action(); 

      spinner.Stop(); 
     } 

     return result; 
    } 
} 

Почему я вижу этот результат иногда?

1 
2 
3 st 0 trtg fdfdfvdgd ] 
4 
[└] test 2 csds fsd fdsf ds s 

Похоже, что Dispose не срабатывал? Или начался новый Task alredy?

Он должен выглядеть следующим образом:

1 
2 
3 
4 
[└] test 2 csds fsd fdsf ds s 

UPDATE:

Я добавил ClearCurrentConsoleLine(); и изменил метод Draw, это исправили проблему.

+0

Я бы предпочел, чтобы он не был потокобезопасным, но как это исправить? – Rumplin

+0

Первые два спящего режима меньше начальной задержки (200 мс). Вот почему первая строка отображает сообщение. Ваши сон происходят в обратном вызове, поэтому все они начинаются параллельно. Вы печатаете статус в текущей позиции консоли, которая изменяется во время выполнения. Hardcode left = 0 и top = 5, и вы увидите желаемый результат. Сказав, я не совсем понимаю, что вы пытаетесь сделать. – ThisGuy

+0

Чтение файлов из общего сетевого ресурса. При этом пользователь увидит, что что-то происходит. Он читает большой объем файла и занимает некоторое время с сетевым ресурсом. «Thread.Sleep» здесь имитирует это. – Rumplin