Я просто хочу знать, как создавать простые анимации, такие как мигание, перемещение материалов на консольных приложениях C#. Есть ли специальный метод для этого?Консольные анимации
ответ
Вы должны будете использовать Console.ForegroundColor
, Console.BackgroundColor
и Console.SetCursorPosition(int, int)
EDIT: Для вдохновения, Let's Dance
Мне очень хотелось бы увидеть кадры анимации Lets Dance как текст, поэтому мы можем реализовать такую анимацию, как консоль Spinner. – TaterJuice
Да, есть quite a few methods для этого.
В частности, вы можете захотеть взглянуть на следующие методы консоли:
- SetCursorPosition (вы можете перемещать курсор, и замены элементов)
- MoveBufferArea (копировать/вставить поверх областей)
- ForegroundColor и BackgroundColor (изменение окраски)
я не слишком уверен, что я точно знаю, что вы на о. но я дам ему шанс. Я думаю, что самый большой и лучший способ вызвать «мигающий» аффект (или то, что я считаю мигающим аффектом) - использовать возврат каретки. Лучший способ объяснить это вам - показать вам эксперимент 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;)
Это, к сожалению, не работает в большинстве случаев. Вы не можете перейти к строке с \ r, поэтому вы очень ограничены, не используя Console.SetCursorPosition –
Ах да, конечно. Я больше не играю в Консоли, я забываю самые очевидные вещи. :) – Skintkingle
Традиционной консоль 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);
}
}
Просто увидел это и несколько других нитей об этом и любит этот вид материала ! Я взял хороший кусок кода 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);
}
}
Я думал, что буду перекликать с моей версией ранее указанного кода. Здесь:
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()
, но, эй), способность цикла анимации вперед и назад (начинает обратное, когда она попадает конец), и общие улучшения в целом. Наслаждайтесь!
Это будет мой Предпочтительнее метод:
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()
, если вы хотите написать больше текста, а затем добавить новый счетчик в новое место.
Вот мой счетчик. Целью этого является, чтобы программа делать какую-то работу в то время как Горячо показывает пользователю, что что-то на самом деле происходит:
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();
Отличная работа с 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);
}
Выход:
Я взял 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
, это исправили проблему.
Я бы предпочел, чтобы он не был потокобезопасным, но как это исправить? – Rumplin
Первые два спящего режима меньше начальной задержки (200 мс). Вот почему первая строка отображает сообщение. Ваши сон происходят в обратном вызове, поэтому все они начинаются параллельно. Вы печатаете статус в текущей позиции консоли, которая изменяется во время выполнения. Hardcode left = 0 и top = 5, и вы увидите желаемый результат. Сказав, я не совсем понимаю, что вы пытаетесь сделать. – ThisGuy
Чтение файлов из общего сетевого ресурса. При этом пользователь увидит, что что-то происходит. Он читает большой объем файла и занимает некоторое время с сетевым ресурсом. «Thread.Sleep» здесь имитирует это. – Rumplin
+1 Loved this question, IMMD =) –