【问题标题】:Set console window size on Windows在 Windows 上设置控制台窗口大小
【发布时间】:2014-11-12 19:08:05
【问题描述】:

我知道有很多关于如何设置控制台大小的问题。但是所有找到的解决方案对我来说都是一样的,而且我的代码对我不起作用。

好的,所以要设置控制台窗口大小,我需要两个函数。他们是SetConsoleScreenBufferSize()SetConsoleWindowInfo()。我的函数的第一个版本:

bool SetWindowSize(size_t width, size_t height)
{
    HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
    if(output_handle == INVALID_HANDLE_VALUE)
        return false;

    COORD coord = {};
    coord.X = static_cast<SHORT>(width);
    coord.Y = static_cast<SHORT>(height);
    if(::SetConsoleScreenBufferSize(output_handle, coord) == FALSE)
        return false;

    SMALL_RECT rect = {};
    rect.Bottom = coord.X - 1;
    rect.Right = coord.Y - 1;
    return (::SetConsoleWindowInfo(output_handle, TRUE, &rect) != FALSE);
}

SetConsoleScreenBufferSize() 不适用于所有值。来自文档:

指定的宽高不能小于宽高 控制台屏幕缓冲区窗口的高度

让我们尝试获取当前窗口的大小并调用我们的函数。要获得窗口大小,我需要GetConsoleScreenBufferInfo() 函数。 main() 测试代码:

HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
if(output_handle == INVALID_HANDLE_VALUE)
    return 0;
CONSOLE_SCREEN_BUFFER_INFO info = {};
if(::GetConsoleScreenBufferInfo(output_handle, &info) == FALSE)
    return 0;
size_t width = info.srWindow.Right - info.srWindow.Left;
size_t height = info.srWindow.Bottom - info.srWindow.Top;
bool suc = SetWindowSize(width + 1, height + 1);

在这种情况下,SetConsoleScreenBufferSize() 工作正常。下一个函数是SetConsoleWindowInfo()。此功能将在以下情况下起作用:

如果指定的窗口矩形超出范围,则函数失败 控制台屏幕缓冲区的边界。这意味着TopLeft 的成员lpConsoleWindow 矩形(或计算 顶部和左侧坐标,如果bAbsolute 为 FALSE) 不能小于 零。同样,BottomRight 成员(或计算 底部和右侧坐标)不能大于(屏幕缓冲区 height – 1) 和 (屏幕缓冲区width – 1) 分别。功能 如果Right 成员(或计算的右坐标)为 小于或等于Left 成员(或计算的左坐标) 或者如果Bottom 成员(或计算的底部坐标)小于 或等于Top 成员(或计算的顶部坐标)。

在我们的例子中,矩形的值与调用GetConsoleScreenBufferInfo() 后的info.srWindow 矩形的值相同(因为LeftTop 为零)。但! SetConsoleWindowInfo() 失败,下一个 ::GetLastError()

@err,hr ERROR_INVALID_PARAMETER : The parameter is incorrect.   unsigned int

如果我交换这两个函数的调用:

bool SetWindowSize(size_t width, size_t height)
{
    HANDLE output_handle = ::GetStdHandle(STD_OUTPUT_HANDLE);
    if(output_handle == INVALID_HANDLE_VALUE)
        return false;

    SMALL_RECT rect = {};
    rect.Bottom = static_cast<SHORT>(width);
    rect.Right = static_cast<SHORT>(height);
    if(::SetConsoleWindowInfo(output_handle, TRUE, &rect) == FALSE)
        return false;

    COORD coord = {};
    coord.X = rect.Bottom + 1;
    coord.Y = rect.Right + 1;

    return (::SetConsoleScreenBufferSize(output_handle, coord) != FALSE);
}

那么我也会有同样的错误。

那么,如何正确使用SetConsoleScreenBufferSize()SetConsoleWindowInfo() 呢?

【问题讨论】:

  • std::minstd::max 是不错的函数。您可以使用它们来计算缓冲区和/或窗口的相关中间大小。记得在包含&lt;windows.h&gt; 之前定义NOMINMAX
  • @Cheersandhth.-Alf,您的评论没有帮助。我知道如何使用 min 和 max 函数。告诉我如何计算缓冲区和/或窗口的相关中间大小以成功使用这两个函数来设置屏幕缓冲区大小和窗口大小
  • @userblahblah:重新“没有帮助”,停止抱怨并开始吧。我已经做过很多次了。所以我知道这是微不足道的,它只是工作。所以,重复一遍,停止抱怨。开始吧。
  • @veryexperienceduser:请给我看一个简单的例子,这对我有用,拜托
  • @user2451677 - 您将rect.bottom 设置为width,将rect.right 设置为height。第一个 sn-p 的第 14 和 15 行。这是故意的吗?

标签: c++ winapi


【解决方案1】:

来自TurboVision port

void TDisplay::setCrtMode( ushort mode )
{
  int oldr = getRows();
  int oldc = getCols();
  int cols = uchar(mode >> 8);
  int rows = uchar(mode);
  if ( cols == 0 ) cols = oldc;
  if ( rows == 0 ) rows = oldr;
  checksize(rows, cols);
  COORD newSize = { cols, rows };
  SMALL_RECT rect = { 0, 0, cols-1, rows-1 };

  if ( oldr <= rows )
  {
    if ( oldc <= cols )
    {                           // increasing both dimensions
BUFWIN:
      SetConsoleScreenBufferSize( TThreads::chandle[cnOutput], newSize );
      SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &rect );
    }
    else
    {                           // cols--, rows+
      SMALL_RECT tmp = { 0, 0, cols-1, oldr-1 };
      SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &tmp );
      goto BUFWIN;
    }
  }
  else
  {
    if ( oldc <= cols )
    {                           // cols+, rows--
      SMALL_RECT tmp = { 0, 0, oldc-1, rows-1 };
      SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &tmp );
      goto BUFWIN;
    }
    else
    {                           // cols--, rows--
      SetConsoleWindowInfo( TThreads::chandle[cnOutput], True, &rect );
      SetConsoleScreenBufferSize( TThreads::chandle[cnOutput], newSize );
    }
  }
  GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
}

ushort TDisplay::getRows()
{
  GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
  return TThreads::sbInfo.dwSize.Y;
}

ushort TDisplay::getCols()
{
  GetConsoleScreenBufferInfo( TThreads::chandle[cnOutput], &TThreads::sbInfo );
  return TThreads::sbInfo.dwSize.X;
}

【讨论】:

  • 在缓冲区之前设置窗口大小,这样就不会使缓冲区小于窗口导致功能失败。
【解决方案2】:

SetConsoleWindowInfo() 不会在屏幕上重新定位控制台窗口。此函数的名称具有误导性。而是滚动控制台窗口内的当前可见部分。请在此处查看this sample

如果要设置运行程序的控制台窗口的位置,请使用如下代码:

HWND hwnd = GetConsoleWindow();
RECT rect = {100, 100, 300, 500};
MoveWindow(hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,TRUE);

【讨论】:

    猜你喜欢
    • 2021-04-25
    • 1970-01-01
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 2021-11-30
    • 2017-04-22
    • 2012-10-11
    相关资源
    最近更新 更多