【问题标题】:How to modify the previous line of console text?如何修改上一行控制台文本?
【发布时间】:2012-06-03 23:26:36
【问题描述】:

我想实现这样的目标:

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

我显示了 3 行文本,每行都与一个线程相关,该线程迟早会结束。但如果第二个比第三个晚完成,我会得到这样的结果:

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

这当然是不可接受的。我知道如何返回当前行,但是有办法向上吗?我发誓我在某个地方见过它,虽然它可能是一个 Linux 控制台 :)

算了。见远文件管理器!它适用于 Windows 控制台,甚至适用于 PowerShell!如何制作这样的东西?最酷的部分是它在退出后恢复控制台状态。所以也许我应该问 - 如何直接访问控制台缓冲区?我想我需要一些本机代码才能做到这一点,但也许还有另一种方法?我想在每次更新时清除控制台,但这似乎有点矫枉过正。或者也许不是?它会闪烁吗?

【问题讨论】:

  • 如果您包含如何“返回当前行”,而不仅仅是声明您知道,那就太好了。我是这样做的:Console.SetCursorPosition(0, Console.CursorTop); 我知道这不是问题的直接部分,但它是相关的,这是我在搜索时发现的问题。

标签: c# powershell console


【解决方案1】:

您可以随意移动光标:Console.SetCursorPosition 或使用Console.CursorTop

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

【讨论】:

  • 是的。就是这个。现在我正在做一个类来将 HTML 中的 DIV 等容器添加到控制台文本中。它会记住每个容器的位置,以便以后更改。现在我终于可以完成我的服务器了 :) 好吧,它仍然是一个插入,但是 Console.MoveBufferArea 将变得很方便。谢谢。
  • 对此请注意:如果您异步更新控制台的不同行,您可能需要添加lock。像这样:stackoverflow.com/a/55520634/2246411
  • 如果你的新文本比原来的短,会发生什么 ;)
【解决方案2】:

使用回车。此示例打印一行,覆盖之前的内容。

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

只要您的所有字符串少于 80 列(或您的终端缓冲区设置的任何值),此方法就可以工作。

【讨论】:

  • 我认为这仅适用于 Windows,但尚未在单声道上尝试过。
  • 它工作得很好,但不能用于向上修改行。然而,这是一种制作单个进度条或百分比更新的简单方法。
【解决方案3】:

注意:以下答案最初是由 OP 编辑​​到问题中的。


这是完整的演示解决方案:

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);
        }
    }
}

【讨论】:

  • Works lekker,您只需要在Replace 方法Items[id] = c; 的末尾再添加一行。这将解决字符开始滚动错误值的连续替换问题。
  • @Pierre 感谢您的评论!我还没有验证代码的正确性,所以它可能存在一些问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-09
  • 2012-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多