【问题标题】:Clear whole Console Without flicker c#清除整个控制台不闪烁c#
【发布时间】:2022-01-01 08:43:45
【问题描述】:

我见过this方法可以清线不闪烁, 但是有没有办法对整个控制台做同样的事情? (而不是使用 Console.Clear)

【问题讨论】:

    标签: c# console-application


    【解决方案1】:

    在没有明确界限的情况下对所有事物做空,然后就这样做

    Console.Clear();
    TitleWithoutSometing();
    

    【讨论】:

    • 这个还是会有闪烁的。
    【解决方案2】:

    您可以使用Console.WindowLeft / Console.WindowTop / Console.WindowHeight / Console.WindowWidth msdn 来获取屏幕缓冲区当前可见区域的大小。

    然后,您只需将这些字符中的每一个替换为您所链接的答案所示的空格即可。

    例如:

    public static void ClearVisibleRegion()
    {
        int cursorTop = Console.CursorTop;
        int cursorLeft = Console.CursorLeft;
        for(int y = Console.WindowTop; y < Console.WindowTop + Console.WindowHeight; y++) {
          Console.SetCursorPosition(Console.WindowLeft, y);
          Console.Write(new string(' ', Console.WindowWidth);
        }
    
        Console.SetCursorPosition(cursorLeft, cursorTop);
    }
    

    这将清除屏幕上当前可见的所有内容并将光标返回到其原始位置。

    如果您希望光标移动到左上角,您可以执行以下操作:

    Console.SetCursorPosition(Console.WindowLeft, Console.WindowTop);
    

    这可能仍会导致闪烁,因为清除所有线条需要一些时间。


    如果您想完全避免闪烁,唯一的方法是绘制您想要在屏幕外显示的任何内容,然后一次复制整个屏幕。这将完全消除任何闪烁。

    您可以通过调用SetCursorPosition() 来完成此操作,其位置在您的WindowLeft / WindowTop / WindowHeight / WindowWidth rect 之外(但仍在BufferHeight / BufferWidth 之内)。

    然后绘制整个窗口的内容。

    然后调用Console.MoveBufferArea()将内容复制到当前窗口区域。

    【讨论】:

      【解决方案3】:

      您可以使用Console.SetCursorPosition,然后覆盖您需要的所有内容:

      public static void Main()
      {
          for (int i = 0; i < 100; i++)
          {
              Console.SetCursorPosition(0, 0);
              Console.WriteLine("Index = " + i);
              System.Threading.Thread.Sleep(500);
          }
      }
      

      您也可以创建自己的函数来自动完成:

      public static void ClearConsole()
      {
          Console.SetCursorPosition(0, 0);
          Console.CursorVisible = false;
          for (int y = 0; y<Console.WindowHeight; y++)
              Console.Write(new String(' ', Console.WindowWidth));
          Console.SetCursorPosition(0, 0);
          Console.CursorVisible = true;
      }
      

      【讨论】:

      • 这可能不会清除当前可见的区域 - 如果您的控制台窗口是 50 行高并且您的程序已经输出了 100 行,那么您只会清除当前不可见的前 50 行。如果要清除整个缓冲区,则需要从 0 循环到 Console.BufferHeight
      • @Turtlefight,好点子。我可能会建议在清除屏幕时隐藏光标,否则,您有时仍会看到一些奇怪的闪烁,但我认为您的答案是正确的。
      • 好点,隐藏光标可能也有帮助:) 和/或为整个区域创建一个大字符串,然后用单个Console.Write() 将其写出来以避免写入之间的刷新。但恕我直言Console.MoveBufferArea() 将是最好的解决方案,因为它基本上保证了整个区域将立即更新 - 但这需要相当多的额外代码才能使其工作:)
      【解决方案4】:

      如果您可以使用最新的 Visual Studio 和 C# 9。如果这是一个仅限 Windows 的项目,我建议您使用一些带有 CsWin32 包的源代码生成器。

      我用它来传送到控制台。性能极佳。

      using Windows.Win32;
      using Windows.Win32.System.Console;
      
          public static void ClearConsole()
          {
              var rows = (short)Console.WindowHeight;
              var cols = (short)Console.WindowWidth;
              SafeFileHandle h = PInvoke.CreateFile("CONOUT$",
                  Windows.Win32.Storage.FileSystem.FILE_ACCESS_FLAGS.FILE_GENERIC_READ | Windows.Win32.Storage.FileSystem.FILE_ACCESS_FLAGS.FILE_GENERIC_WRITE,
                  Windows.Win32.Storage.FileSystem.FILE_SHARE_MODE.FILE_SHARE_WRITE,
                  null,
                  Windows.Win32.Storage.FileSystem.FILE_CREATION_DISPOSITION.OPEN_EXISTING,
                  Windows.Win32.Storage.FileSystem.FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL,
                  null
                  );
      
      
              if (!h.IsInvalid)
              {
                  var screenBuffer = new CHAR_INFO[rows * cols];
      
                  var writeRegion = new SMALL_RECT
                  {
                      Left = 0,
                      Top = 0,
                      Right = (short)(cols),
                      Bottom = (short)(rows)
                  };
                  for (int y = 0; y < rows; y++)
                  {
                      for (int x = 0; x < cols; x++)
                      {
                          screenBuffer[y * cols + x].Attributes = (byte)Console.BackgroundColor;
                          //buf[y * cols + x].Char.UnicodeChar = '';
                      }
                  }
                  PInvoke.WriteConsoleOutput(
                      h,
                      screenBuffer[0],
                      new COORD { X = cols, Y = rows },
                      new COORD(),
                      ref writeRegion
                      );
              }
          }
      

      我的NativeMethods.txt 文件:

      CreateFile
      WriteConsoleOutput
      

      Ofc,您不必使用这些库。现在好多了。我之前设置了自己的对 Kernel32.dll 的 pinvoke 调用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-14
        • 1970-01-01
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多