Консольное приложение: как обновить дисплей без мерцания? - PullRequest
12 голосов
/ 25 марта 2011

Использование C # 4 в консольном приложении Windows, которое постоянно сообщает о прогрессе. Как сделать «перерисовку» экрана более плавной?

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

В настоящее время я переписываю весь текст (название приложения и т. Д.). Как это:

Console.Clear();
WriteTitle();
Console.WriteLine();
Console.WriteLine("Deleting:\t{0} of {1} ({2})".FormatString(count.ToString("N0"), total.ToString("N0"), (count / (decimal)total).ToString("P2")));

Что вызывает много мерцания.

Ответы [ 7 ]

15 голосов
/ 25 марта 2011

Попробуйте Console.SetCursorPosition. Подробнее здесь: Как обновить текущую строку в консольном приложении C # Windows?

6 голосов
/ 25 марта 2011
static void Main(string[] args)
{
    Console.SetCursorPosition(0, 0);
    Console.Write("################################");
    for (int row = 1; row < 10; row++)
    {
        Console.SetCursorPosition(0, row);
        Console.Write("#                              #");
    }
    Console.SetCursorPosition(0, 10);
    Console.Write("################################");

    int data = 1;
    System.Diagnostics.Stopwatch clock = new System.Diagnostics.Stopwatch();
    clock.Start();
    while (true)
    {
        data++;
        Console.SetCursorPosition(1, 2);
        Console.Write("Current Value: " + data.ToString());
        Console.SetCursorPosition(1, 3);
        Console.Write("Running Time: " + clock.Elapsed.TotalSeconds.ToString());
        Thread.Sleep(1000);
    }

    Console.ReadKey();
}
5 голосов
/ 17 ноября 2012

Я знаю, что этот вопрос немного устарел, но я обнаружил, что если вы установите Console.CursorVisible = false, то мерцание также прекратится.

0 голосов
/ 01 августа 2018

Я бы порекомендовал следующие методы расширения.Они позволяют вам использовать StringBuilder для обновления представления консоли без мерцания, а также приводят в порядок все остаточные символы в каждой строке

Проблема : следующая демонстрация демонстрирует использование стандартного StringBuilderгде обновление строк, которые короче, чем ранее написанная строка, перемешивается.Это делается путем написания короткой строки, затем длинной строки в цикле:

public static void Main(string[] args)
{            
   var switchTextLength = false;

   while(true)
   {
       var sb = new StringBuilder();       

       if (switchTextLength)
            sb.AppendLine("Short msg");
       else
            sb.AppendLine("Longer message");

       sb.UpdateConsole();

       switchTextLength = !switchTextLength;
       Thread.Sleep(500);
   }
}

Результат:

The remainder of the longer string still exists because the shorter message is not long enough to overwrite it

Решение : с помощью метода расширения, описанного ниже, проблема решена

public static void Main(string[] args)
{            
   var switchTextLength = false;

   while(true)
   {
       var sb = new StringBuilder();       

       if (switchTextLength)
            sb.AppendLineEx("Short msg");
       else
            sb.AppendLineEx("Longer message");

       sb.UpdateConsole();

       switchTextLength = !switchTextLength;
       Thread.Sleep(500);
   }
}

Результат:

The shorter line is written out, and the rest of the buffer space is overwritten with empty space

Методы расширения:

public static class StringBuilderExtensions
{
    /// <summary>
    /// Allows StrinbBuilder callers to append a line and blank out the remaining characters for the length of the console buffer width
    /// </summary>
    public static void AppendLineEx(this StringBuilder c, string msg)
    {
        // Append the actual line
        c.Append(msg);
        // Add blanking chars for the rest of the buffer
        c.Append(' ', Console.BufferWidth - msg.Length - 1);
        // Finish the line
        c.Append(Environment.NewLine);
    }

    /// <summary>
    /// Combines two StringBuilders using AppendLineEx
    /// </summary>
    public static void AppendEx(this StringBuilder c, StringBuilder toAdd)
    {
        foreach (var line in toAdd.ReadLines())
        {
            c.AppendLineEx(line);
        }
    }

    /// <summary>
    /// Hides the console cursor, resets its position and writes out the string builder
    /// </summary>
    public static void UpdateConsole(this StringBuilder c)
    {
        // Ensure the cursor is hidden
        if (Console.CursorVisible) Console.CursorVisible = false;

        // Reset the cursor position to the top of the console and write out the string builder
        Console.SetCursorPosition(0, 0);
        Console.WriteLine(c);
    }
}
0 голосов
/ 23 ноября 2017

Вот простая рабочая демонстрация, которая показывает многострочное использование без мерцания.Он показывает текущее время и случайную строку каждую секунду.

    private static void StatusUpdate()
    {
        var whiteSpace = new StringBuilder();
        whiteSpace.Append(' ', 10);
        var random = new Random();
        const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        var randomWord = new string(Enumerable.Repeat(chars, random.Next(10)).Select(s => s[random.Next(s.Length)]).ToArray());
        while (true)
        {
            Console.SetCursorPosition(0, 0);
            var sb = new StringBuilder();
            sb.AppendLine($"Program Status:{whiteSpace}");
            sb.AppendLine("-------------------------------");
            sb.AppendLine($"Last Updated: {DateTime.Now}{whiteSpace}");
            sb.AppendLine($"Random Word: {randomWord}{whiteSpace}");
            sb.AppendLine("-------------------------------");
            Console.Write(sb);
            Thread.Sleep(1000);
        }
    }

В приведенном выше примере предполагается, что ваше окно консоли пусто для запуска.Если нет, сначала используйте Console.Clear ().

Техническое примечание: SetCursorPosition (0,0) помещает курсор обратно на вершину (0,0), поэтому следующий вызов Console.Write начнется со строки 0, символ 0.Обратите внимание, что предыдущий контент не удаляется перед записью.Например, если вы напишите «asdf» поверх предыдущей строки, такой как «0123456», вы получите что-то вроде «asdf456» в этой строке.По этой причине мы используем переменную whiteSpace, чтобы гарантировать, что любые оставшиеся символы из предыдущей строки будут перезаписаны пробелами.Отрегулируйте длину переменной whiteSpace в соответствии с вашими потребностями.Вам нужна переменная whiteSpace только для строк, которые меняются.

Личное примечание: Для моих целей я хотел показать текущее состояние приложений (раз в секунду) вместе с кучей другой информации о состоянии, и я хотел избежать любых раздражающих мерцаний, которые могутслучается, когда вы используете Console.Clear ().В моем приложении я запускаю обновления своего статуса в отдельном потоке, поэтому он постоянно предоставляет обновления, несмотря на то, что у меня одновременно работают многочисленные другие потоки и долго выполняющиеся задачи.к предыдущим постерам и dtb для генератора случайных строк, используемого в демо. Как я могу генерировать случайные буквенно-цифровые строки в C #?

0 голосов
/ 25 марта 2011

Я думаю, что вы можете использовать \ r в консоли Windows, чтобы вернуть начало строки. Вы также можете использовать SetCursorPosition.

0 голосов
/ 25 марта 2011

Вы можете попытаться что-то взломать, используя базовые библиотеки.

Вместо того, чтобы тратить свое время на некондиционные результаты, я бы проверил этот порт C # библиотеки ncurses (которая используется дляформатирование вывода консоли):

Curses Sharp

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...