Deleting previously written lines in Console

后端 未结 2 407
醉梦人生
醉梦人生 2020-12-10 19:54

Is there anyway to delete certain parts of a console window using the (Left,Top) coordinates used with Console.SetCursorPosition()?

Could you make a custom method fo

相关标签:
2条回答
  • 2020-12-10 20:23

    If performance is a concern you can directly manipulate the console buffer. Unfortuantely this will require some interop, here is an example that I have adapted from a previous answer I gave. This will clear an area of the console buffer very quickly. It is a bit lengthy because of the interop, but if you wrap this nicely into a console helper class you can extend it to do all kinds of high performance console output.

    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using Microsoft.Win32.SafeHandles;
    
    namespace ConsoleApplication1
    {
      class Program
      {
        [STAThread]
        static void Main(string[] args)
        {
          Console.SetCursorPosition(0, 0);
          for (int x = 0; x < 80 * 25; ++x)
          {
            Console.Write("A");
          }
          Console.SetCursorPosition(0, 0);
    
          Console.ReadKey(true);
    
          ClearArea(1, 1, 78, 23);
    
          Console.ReadKey();
        }
    
        static void ClearArea(short left, short top, short width, short height)
        {
          ClearArea(left, top, width, height, new CharInfo() { Char = new CharUnion() { AsciiChar = 32 } });
        }
    
        static void ClearArea(short left, short top, short width, short height, CharInfo charAttr)
        {
          using (SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero))
          {
            if (!h.IsInvalid)
            {
              CharInfo[] buf = new CharInfo[width * height];
              for (int i = 0; i < buf.Length; ++i)
              {
                buf[i] = charAttr;
              }
    
              SmallRect rect = new SmallRect() { Left = left, Top = top, Right = (short)(left + width), Bottom = (short)(top + height) };
              WriteConsoleOutput(h, buf,
                new Coord() { X = width, Y = height },
                new Coord() { X = 0, Y = 0 },
                ref rect);
            }
          }
        }
    
        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern SafeFileHandle CreateFile(
            string fileName,
            [MarshalAs(UnmanagedType.U4)] uint fileAccess,
            [MarshalAs(UnmanagedType.U4)] uint fileShare,
            IntPtr securityAttributes,
            [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
            [MarshalAs(UnmanagedType.U4)] int flags,
            IntPtr template);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);
    
        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool WriteConsoleOutput(
          SafeFileHandle hConsoleOutput,
          CharInfo[] lpBuffer,
          Coord dwBufferSize,
          Coord dwBufferCoord,
          ref SmallRect lpWriteRegion);
    
        [StructLayout(LayoutKind.Sequential)]
        public struct Coord
        {
          public short X;
          public short Y;
    
          public Coord(short X, short Y)
          {
            this.X = X;
            this.Y = Y;
          }
        };
    
        [StructLayout(LayoutKind.Explicit)]
        public struct CharUnion
        {
          [FieldOffset(0)]
          public char UnicodeChar;
          [FieldOffset(0)]
          public byte AsciiChar;
        }
    
        [StructLayout(LayoutKind.Explicit)]
        public struct CharInfo
        {
          [FieldOffset(0)]
          public CharUnion Char;
          [FieldOffset(2)]
          public short Attributes;
        }
    
        [StructLayout(LayoutKind.Sequential)]
        public struct SmallRect
        {
          public short Left;
          public short Top;
          public short Right;
          public short Bottom;
        }   
      }
    }
    
    0 讨论(0)
  • 2020-12-10 20:32

    Silky's comment is the right answer:

    • Set an appropriate background colour
    • Loop for each line you wish to clear part of:
      • Set the cursor position to left hand side
      • Write out a string of spaces of the right width

    For example:

    public static void ClearArea(int top, int left, int height, int width) 
    {
        ConsoleColor colorBefore = Console.BackgroundColor;
        try
        {
            Console.BackgroundColor = ConsoleColor.Black;
            string spaces = new string(' ', width);
            for (int i = 0; i < height; i++)
            {
                Console.SetCursorPosition(left, top + i);
                Console.Write(spaces);
            }
        }
        finally
        {
            Console.BackgroundColor = colorBefore;
        }
    }
    

    Note that this will restore the background colour, but not the previous cursor location.

    0 讨论(0)
提交回复
热议问题