【问题标题】:How to resize a Windows 10 window and ignore the transparent border?如何调整 Windows 10 窗口的大小并忽略透明边框?
【发布时间】:2017-12-06 17:13:52
【问题描述】:

我们的 3d 应用程序窗口需要覆盖用户的整个桌面,包括任务栏(不能调整大小,不能最大化,不能像视频游戏中看到的那样全屏 , 只是右上角带有 [X] 的窗口、标题栏和状态栏)。

为此,我们使用了以下代码:

void
CTheApp::SetFullScreenMode()
{
  HWND hwnd = getHandle();

  long style = ::GetWindowLong(hwnd, GWL_STYLE);
  style &= ~(WS_MAXIMIZEBOX|WS_MINIMIZEBOX|WS_THICKFRAME);
  ::SetWindowLong(hwnd, GWL_STYLE, style);

  // get screen dimensions
  int width  = ::GetSystemMetrics(SM_CXSCREEN);
  int height = ::GetSystemMetrics(SM_CYSCREEN);

  ::MoveWindow(hwnd, 0, 0, width, height, TRUE);
}

它满足了我们的需求...直到 Windows 10 到来。

在 Windows 10 中,左侧、右侧和底部有一个窗口没有覆盖的小间隙。 (更准确地说:左边9个像素,右边9个像素,底部9个像素。)

Windows 10 似乎在非最大化窗口的边框上添加了这种透明样式。

我怎样才能使窗口在 Windows 10 的整个屏幕上视觉上正确拉伸(不留明显间隙),同时保持该功能对以前版本的 Windows(Windows 7 - Windows 8.1)有效?有没有一种干净的方法可以将此“透明度”设置为零?


我考虑过修改它并将每边的大小扩大 9 个像素,但是当用户设置另一个主题(例如高对比度)或应用程序将在多个显示器上使用多个窗口时,这可能会导致问题.

【问题讨论】:

标签: c++ window windows-10


【解决方案1】:

我找到了两种方法来实现这一点。

通过使用DwmGetWindowAttribute 函数

通过这种方法,我们MoveWindow 两次。我们第一次移动它将定位窗口并计算其所有大小信息。这将使我们能够获得其维度的两个方面。第二次,我们将考虑“投影”边框。为此,我们需要ShowWindow( SW_SHOW );之前我们MoveWindow

void MyCFrameWndMain::applyWindowSizeAndShow()
{
  ShowWindow( SW_SHOW );
  
  int targetWidth = ::GetSystemMetrics( SM_CXSCREEN );
  int targetHeight = ::GetSystemMetrics( SM_CYSCREEN );

  MoveWindow( 0, 0, targetWidth, targetHeight, TRUE );
  
  RECT decoratedRect;
  // This gets the rectangle "with the decoration":
  GetWindowRect( &decoratedRect ); 
  RECT leanRECT;
  // This gets the rectangle "without the decoration":
  ::DwmGetWindowAttribute( m_hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, &leanRECT, sizeof( leanRECT ) ); 
  
  int leftDecoration   = leanRECT.left        - decoratedRect.left;
  int rightDecoration  = decoratedRect.right  - leanRECT.right;
  int topDecoration    = leanRECT.top         - decoratedRect.top;
  int bottomDecoration = decoratedRect.bottom - leanRECT.bottom;
  
  // Apparently, the "rectangle without the decoration" still has a 1 pixel border on the sides and 
  // at the bottom, so we use the GetSystemMetrics to figure out the size of that border, and 
  // correct the size.
  int xBorder = ::GetSystemMetrics( SM_CXBORDER );
  int yBorder = ::GetSystemMetrics( SM_CYBORDER );

  MoveWindow( 
    0 - leftDecoration - xBorder
    , 0 - topDecoration - yBorder
    , targetWidth + leftDecoration + rightDecoration + 2*xBorder
    , targetHeight + topDecoration + bottomDecoration + 2*yBorder
    , TRUE );
}

这种方法似乎比其他方法效果更好。

通过处理WM_NCCALCSIZE 消息

使用这种方法,思路是在MoveWindow之前显示出来。

void MyCFrameWndMain::applyWindowSizeAndShow()
{
  int targetWidth = ::GetSystemMetrics( SM_CXSCREEN );
  int targetHeight = ::GetSystemMetrics( SM_CYSCREEN );

  MoveWindow( 0, 0, targetWidth, targetHeight, TRUE );

  ShowWindow( SW_SHOW );
}

然后处理WM_NCCALCSIZE消息:

LRESULT MyCFrameWndMain::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
  
  // ...
  
  case WM_NCCALCSIZE:
  { // https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize?redirectedfrom=MSDN
    int titleBarHeight = ::GetSystemMetrics( SM_CYCAPTION );
    if ( wParam == TRUE )
    {
      NCCALCSIZE_PARAMS* params = reinterpret_cast<NCCALCSIZE_PARAMS*>( lParam );
      params->rgrc[0].top = titleBarHeight;
      return WVR_REDRAW;
    }
    else //if ( wParam == FALSE )
    {
      RECT* rect = reinterpret_cast<RECT*>( lParam );
      rect->top = titleBarHeight;
      return 0;
    }
  }
  break;

  // ...

  }
}

我发现使用这种方法的缺点:

  • 在窗口的上边缘和屏幕的上边缘之间有一像素线
  • 当我有两台未使用相同缩放比例的显示器(例如,主显示器为 150%,第二台为 100%)时,当我使用标题栏将窗口从一台显示器拖动到另一台显示器时,标题栏会消失,一切都会一团糟。当两者都为 100% 时,我无法重现此问题。当典型用法是不移动窗口(我们的例子)时,这应该不是问题。
  • 我想我不太确定这一切是如何工作的,但似乎某些窗口元素有点不合适。

如果我没有找到第一种方法,那么第二种方法可以很好地满足我们的需求,即使它有几个问题。


我已经使用了这些答案(以及其他资源):

【讨论】:

    【解决方案2】:

    这由Desktop Window Manager 处理并且可以被覆盖。主要步骤是 WM_NCCALCSIZE(窗口消息,非客户端),您覆盖它以返回 0,0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 2013-07-12
      • 2011-09-22
      • 2012-08-09
      • 1970-01-01
      • 2017-09-16
      • 1970-01-01
      相关资源
      最近更新 更多