gpt4 book ai didi

c++ - 带投影的无边框窗口

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:17:40 25 4
gpt4 key购买 nike

我正在尝试实现类似 Visual Studio 安装程序对无边框窗口和投影的效果:

screenshot

我尝试了各种选项,如 CS_DROPSHADOW 和 DWM API,但只要我应用 WS_THICKFRAME 样式,阴影就会消失。

这是我创建和居中窗口的代码:

RECT R = {0, 0, _clientWidth, _clientHeight};
AdjustWindowRect(&R, WS_OVERLAPPEDWINDOW, false);
_mainWnd = CreateWindow(L"D3DWndClassName", _mainWndCaption.c_str(), WS_OVERLAPPEDWINDOW, 100, 100, R.right, R.bottom, nullptr, nullptr, _appInst, nullptr);

if(!_mainWnd){
MessageBox(nullptr, L"CreateWindow FAILED", nullptr, 0);
PostQuitMessage(0);
}

RECT rc;

GetWindowRect(_mainWnd, &rc);

LONG lStyle = GetWindowLong(_mainWnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU );
SetWindowLong(_mainWnd, GWL_STYLE, lStyle);


int xPos = (GetSystemMetrics(SM_CXSCREEN) - rc.right) / 2;
int yPos = (GetSystemMetrics(SM_CYSCREEN) - rc.bottom) / 2;

SetWindowPos(_mainWnd, 0, xPos, yPos, _clientWidth, _clientHeight, SWP_NOZORDER);

ShowWindow(_mainWnd, SW_SHOW);
UpdateWindow(_mainWnd);

最佳答案

如果 wParam 为 TRUE,您可以通过组合使用 DwmExtendFrameIntoClientArea() 并设置 0 作为 WM_NCCALCSIZE 的消息结果来创建此效果。详细步骤如下。

  • 窗口样式应该是这样的,通常整个框架都会显示(WS_CAPTION|WS_POPUP 对我来说效果很好),但不要包含任何 WS_MINIMIZEWS_MAXIMIZEWS_SYSMENU
  • 使用 MARGINS{0,0,0,1} 调用 DwmExtendFrameIntoClientArea()。我们真的不想要透明框架,所以只设置底部边距就足够了。
  • 调用SetWindowPos(hWnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOOWNERZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_FRAMECHANGED)让系统重新计算NC区域。
  • 如果 wParam 为 TRUE,则从 WM_NCCALCSIZE 返回 0。这具有将客户区扩展到包括框架在内的窗口大小但不包括阴影的效果。请参阅文档的备注部分。
  • WM_PAINT 中绘制您喜欢的框架和内容区域,但请确保为由 DwmExtendFrameIntoClientArea() 调用。否则部分常规框架将在此区域可见。您可以为此使用 GDI+,因为大多数常规 GDI 函数会忽略 alpha channel 。 BitBlt() 也可以使用包含不透明 alpha channel 的 32bpp 源位图。
  • 如果您想要一个可调整大小的窗口,您可以处理 WM_NCHITTEST

所有这一切的效果是,由于 DWM 调用,您“覆盖”了现在位于客户区内的常规窗口框架,但保持常规窗口阴影。不要担心“重绘”不会产生任何闪烁,即使您使窗口可调整大小也是如此。

您可以将任何标准或用户定义的控件放入此窗口。只需确保子控件不与 DwmExtendFrameIntoClientArea() 调用定义的边距重叠,因为大多数基于 GDI 的控件会忽略 alpha channel 。

这是一个最小的、独立的示例应用程序:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <dwmapi.h>
#include <unknwn.h>
#include <gdiplus.h>
#pragma comment( lib, "dwmapi" )
#pragma comment( lib, "gdiplus" )
namespace gdip = Gdiplus;

INT_PTR CALLBACK MyDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam );

int APIENTRY wWinMain( _In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow )
{
// Initialize GDI+
gdip::GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdipToken = 0;
gdip::GdiplusStartup( &gdipToken, &gdiplusStartupInput, nullptr );

struct MyDialog : DLGTEMPLATE {
WORD dummy[ 3 ] = { 0 }; // unused menu, class and title
}
dlg;
dlg.style = WS_POPUP | WS_CAPTION | DS_CENTER;
dlg.dwExtendedStyle = 0;
dlg.cdit = 0; // no controls in template
dlg.x = 0;
dlg.y = 0;
dlg.cx = 300; // width in dialog units
dlg.cy = 200; // height in dialog units

DialogBoxIndirectW( hInstance, &dlg, nullptr, MyDialogProc );

gdip::GdiplusShutdown( gdipToken );

return 0;
}

INT_PTR CALLBACK MyDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_INITDIALOG:
{
SetWindowTextW( hDlg, L"Borderless Window with Shadow" );

// This plays together with WM_NCALCSIZE.
MARGINS m{ 0, 0, 0, 1 };
DwmExtendFrameIntoClientArea( hDlg, &m );

// Force the system to recalculate NC area (making it send WM_NCCALCSIZE).
SetWindowPos( hDlg, nullptr, 0, 0, 0, 0,
SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED );
return TRUE;
}
case WM_NCCALCSIZE:
{
// Setting 0 as the message result when wParam is TRUE removes the
// standard frame, but keeps the window shadow.
if( wParam == TRUE )
{
SetWindowLong( hDlg, DWLP_MSGRESULT, 0 );
return TRUE;
}
return FALSE;
}
case WM_PAINT:
{
PAINTSTRUCT ps{ 0 };
HDC hdc = BeginPaint( hDlg, &ps );

// Draw with GDI+ to make sure the alpha channel is opaque.
gdip::Graphics gfx{ hdc };
gdip::SolidBrush brush{ gdip::Color{ 255, 255, 255 } };
gfx.FillRectangle( &brush,
static_cast<INT>( ps.rcPaint.left ), static_cast<INT>( ps.rcPaint.top ),
static_cast<INT>( ps.rcPaint.right - ps.rcPaint.left ), static_cast<INT>( ps.rcPaint.bottom - ps.rcPaint.top ) );

EndPaint( hDlg, &ps );
return TRUE;
}
case WM_NCHITTEST:
{
// Setting HTCAPTION as the message result allows the user to move
// the window around by clicking anywhere within the window.
// Depending on the mouse coordinates passed in LPARAM, you may
// set other values to enable resizing.
SetWindowLong( hDlg, DWLP_MSGRESULT, HTCAPTION );
return TRUE;
}
case WM_COMMAND:
{
WORD id = LOWORD( wParam );
if( id == IDOK || id == IDCANCEL )
{
EndDialog( hDlg, id );
return TRUE;
}
return FALSE;
}
}
return FALSE; // return FALSE to let DefDialogProc handle the message
}

关于c++ - 带投影的无边框窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43818022/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com