Как записать символ в консоль не передвигая курсор?
Есть код:
Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
Console.Write("╔");
for (int i = 0; i < Console.WindowWidth - 2; i++)
Console.Write("═");
Console.Write("╗");
for(int i = 0; i < Console.WindowHeight - 2; i++)
{
Console.Write("║");
for (int j = 0; j < Console.WindowWidth - 2; j++)
Console.Write(" ");
Console.Write("║");
}
Console.Write("╚");
for (int i = 0; i < Console.WindowWidth - 2; i++)
Console.Write("═");
Console.Write("╝");
Которая должна выводить рамку в консоль, но первая строка стирается т.к. происходит переход на следующую строку:
Как убрать этот переход, чтобы было так, но с символом "╝" в конце:
Ответы (1 шт):
Класс Console не представляет такой возможности, поэтому потребуется использовать Win API. Я нашел метод kernel32.dll - WriteConsoleOutputCharacter.
Для того чтобы им воспользоваться, написал вот такой класс.
public static class ConsoleHelper
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
private static extern bool WriteConsoleOutputCharacter(IntPtr hConsoleOutput, string lpCharacter, uint nLength, Point16 dwWriteCoord, out uint lpNumberOfCharsWritten);
[DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int nStdHandle);
private const int STD_OUTPUT_HANDLE = -11;
private const int STD_INPUT_HANDLE = -10;
private const int STD_ERROR_HANDLE = -12;
private static readonly IntPtr _stdOut = GetStdHandle(STD_OUTPUT_HANDLE);
[StructLayout(LayoutKind.Sequential)]
private struct Point16
{
public short X;
public short Y;
public Point16(short x, short y)
=> (X, Y) = (x, y);
};
public static void WriteToBufferAt(string text, int x, int y)
{
WriteConsoleOutputCharacter(_stdOut, text, (uint)text.Length, new Point16((short)x, (short)y), out uint _);
}
}
По сути метод WriteToBufferAt пишет текст в консоль по указанным координатам, и при этом никак не двигает курсор.
Ваш код немного упростил, потому что вы делали очень много вызовов записи в консоль, а это медленно.
class Program
{
static void Main(string[] args)
{
Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
Console.Write("╔");
Console.Write(new string('═', Console.WindowWidth - 2));
Console.Write("╗");
for (int i = 0; i < Console.WindowHeight - 2; i++)
{
Console.Write("║");
Console.Write(new string(' ', Console.WindowWidth - 2));
Console.Write("║");
}
Console.Write("╚");
Console.Write(new string('═', Console.WindowWidth - 2));
ConsoleHelper.WriteToBufferAt("╝", Console.WindowWidth - 1, Console.WindowHeight - 1);
Console.ReadKey(true);
}
}
А вообще можно сократить количество записей в консоль до одного вызова.
static void Main(string[] args)
{
Console.SetBufferSize(Console.WindowWidth, Console.WindowHeight);
StringBuilder sb = new StringBuilder();
string hRow = new string('═', Console.WindowWidth - 2);
string blankRow = new string(' ', Console.WindowWidth - 2);
sb.Append('╔').Append(hRow).Append('╗');
for (int i = 0; i < Console.WindowHeight - 2; i++)
{
sb.Append('║').Append(blankRow).Append('║');
}
sb.Append('╚').Append(hRow).Append('╝');
ConsoleHelper.WriteToBufferAt(sb.ToString(), 0, 0);
Console.ReadKey(true);
}
Данный способ вывода символов не поддерживает изменение цвета в консоли, то есть выводимый символ будет того цвета, который был уже ранее задан в целевом знакоместе. Если нужна зеленая рамочка, то можно считерить следующим образом изменив самое начало кода:
Console.ForegroundColor = ConsoleColor.Green;
Console.Clear();


