如何将控制台窗口的大小调整为设定的行数和列数?

Posted

技术标签:

【中文标题】如何将控制台窗口的大小调整为设定的行数和列数?【英文标题】:How do I resize the console window to a set number of rows and columns? 【发布时间】:2021-08-26 17:07:23 【问题描述】:

我正在使用 windows.h 包含为 Windows 编写一个 c++ 控制台程序。

我一直在尝试调整控制台大小以适合我的程序输出,但没有找到可靠的方法来获取“单元格”(字符框)的宽度和高度值。我已经尝试过 GetConsoleFontSize 和 GetConsoleScreenBufferInfo + GetDesktopWindow,如下面的代码示例所示。

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);

    CONSOLE_FONT_INFO font_size;
    GetConsoleFontSize(hOut,GetCurrentConsoleFont(hOut, false, &font_size));

    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(hOut, &csbi);

    RECT desktop;
    // Get a handle to the desktop window
    const HWND hDesktop = GetDesktopWindow();
    // Get the size of screen to the variable desktop
    GetWindowRect(hDesktop, &desktop);

    // Calculate size of one cell in the console, expressed in pixels.
    COORD cell;
    // Screen width/max number of columns
    cell.X = desktop.right/ csbi.dwMaximumWindowSize.X;
    // Screen height/max number of rows
    cell.Y = desktop.bottom / csbi.dwMaximumWindowSize.Y;    

    // Change console size
    HWND console = GetConsoleWindow();
    MoveWindow(console, 0, 0, 10 * cell.X * 2, 10 * cell.Y, TRUE);
    MoveWindow(console, 0, 0, 10 * font_size.dwFontSize.X * 2, 10 * font_size.dwFontSize.Y, TRUE);

在这两种尝试中,我希望一个方形窗口能够仅包含大约 20x10 个单元格(单元格的高度似乎是宽度的 2 倍),在给定整数除法的情况下,其中一个示例存在一定的误差。但是,它们似乎都太小了大约 25%,除了第一个示例的宽度大约太大了 10%。

我假设字体大小不包括字母之间的间距,并且 .dwMaxWindowSize 的依赖关系(例如缓冲区大小等)起作用,但我不能完全理解这两种方法。

如果有人知道如何可靠地获取单元格的宽度/高度(以像素为单位),我将不胜感激。关于单元格中的内容、影响函数返回值的任何信息或我可以用来实现目标的其他函数。

还要注意,最终大小会变大,但由于我想手动计算行/列以进行调试,所以我将其变小了。

【问题讨论】:

使用GetClientRect 只计算窗口的客户区而不是窗口的总大小可能会有所帮助。 docs.microsoft.com/en-us/windows/win32/api/winuser/…。此外,如果您只使用newClientWidth = oldClientWidth * newBufferColumns / oldBufferColumns 并且与高度/行相同,您可能不需要字体大小。要设置窗口大小,您可能需要在客户端大小和窗口大小之间进行转换,但我认为这是一个恒定的差异:newWindowWidth = newClientWidth + oldWindowWidth - oldClientWidth 或类似的东西。 @Ruzihm 谢谢!我也不确定为什么该问题被标记为重复,因为它似乎比链接的问题更复杂。我错过了什么吗? 我同意这不是重复的,我投票重新开放 现在问题已经重新打开,我已经删除了解决方案以及问题中的评论。如果需要,请随时发布解决方案作为答案。您可以通过单击编辑按钮并从修订历史中复制文本来访问以前的编辑,因此您不必再次输入。 @Ruzihm 我用完成的解决方案更新了这个问题。由于接种了疫苗,我已经有点不适应了,所以自从我发布这个问题以来,我并没有真正取得太大进展。至少我觉得我现在走在正确的轨道上,非常感谢! 【参考方案1】:

我现在几乎有了解决方案,但还需要一些工作。

CONSOLE_SCREEN_BUFFER_INFO csbi;
HWND console = GetConsoleWindow();
// Resolution
RECT newClientSize, oldClientSize, newWindowSize, oldWindowSize;
// Colums, Rows
COORD newBuffer20,50, oldBuffer;

for (int i = 0; i < 2; i++) 
    // Calculate the starting amount of columns and rows.
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    oldBuffer.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
    oldBuffer.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;

    printf("%i\n", oldBuffer.X);
    printf("%i\n", oldBuffer.Y);
    
    // Get size of client area
    GetClientRect(console, &oldClientSize);
    
    newClientSize.right = oldClientSize.right * newBuffer.X / oldBuffer.X;
    newClientSize.bottom = oldClientSize.bottom * newBuffer.Y / oldBuffer.Y;

    // Get size of window area
    GetWindowRect(console, &oldWindowSize);

    newWindowSize.right = newClientSize.right + oldWindowSize.right - oldClientSize.right;
    newWindowSize.bottom = newClientSize.bottom + oldWindowSize.bottom - oldClientSize.bottom;

    MoveWindow(console, 0, 0, newWindowSize.right, newWindowSize.bottom, TRUE);



GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
oldBuffer.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
oldBuffer.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;

printf("%i\n", oldBuffer.X);
printf("%i\n", oldBuffer.Y);

我不明白为什么当我重复代码两次或更多次时它会起作用。唯一我不认为我完全理解的是 ClientRectWindowRect 之间的区别。但是,与往常一样,我可能还缺少其他东西。

【讨论】:

以上是关于如何将控制台窗口的大小调整为设定的行数和列数?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取ResultSet的行数和列数

是否可以根据屏幕宽度使用gridLayoutManager调整recyclerview的行数和列数?

如何在 C++ 中获取二维动态数组的行数和列数

如何查找 MinMaxScaler 对象中的行数和列数?

Java 数组 获取二维数组的行数和列数

VBA中如何获取一个表格的行数和列数